2023-03-21 06:26:07 +00:00
|
|
|
#include "git-compat-util.h"
|
2021-10-29 00:15:52 +00:00
|
|
|
#include "config.h"
|
write_or_die: handle EPIPE in async threads
When write_or_die() sees EPIPE, it treats it specially by
converting it into a SIGPIPE death. We obviously cannot
ignore it, as the write has failed and the caller expects us
to die. But likewise, we cannot just call die(), because
printing any message at all would be a nuisance during
normal operations.
However, this is a problem if write_or_die() is called from
a thread. Our raised signal ends up killing the whole
process, when logically we just need to kill the thread
(after all, if we are ignoring SIGPIPE, there is good reason
to think that the main thread is expecting to handle it).
Inside an async thread, the die() code already does the
right thing, because we use our custom die_async() routine,
which calls pthread_join(). So ideally we would piggy-back
on that, and simply call:
die_quietly_with_code(141);
or similar. But refactoring the die code to do this is
surprisingly non-trivial. The die_routines themselves handle
both printing and the decision of the exit code. Every one
of them would have to be modified to take new parameters for
the code, and to tell us to be quiet.
Instead, we can just teach write_or_die() to check for the
async case and handle it specially. We do have to build an
interface to abstract the async exit, but it's simple and
self-contained. If we had many call-sites that wanted to do
this die_quietly_with_code(), this approach wouldn't scale
as well, but we don't. This is the only place where do this
weird exit trick.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-24 07:40:16 +00:00
|
|
|
#include "run-command.h"
|
2023-03-21 06:26:01 +00:00
|
|
|
#include "wrapper.h"
|
2023-03-21 06:26:07 +00:00
|
|
|
#include "write-or-die.h"
|
2006-08-21 18:43:43 +00:00
|
|
|
|
2007-06-29 17:40:46 +00:00
|
|
|
/*
|
|
|
|
* Some cases use stdio, but want to flush after the write
|
|
|
|
* to get error handling (and to get better interactive
|
|
|
|
* behaviour - not buffering excessively).
|
|
|
|
*
|
|
|
|
* Of course, if the flush happened within the write itself,
|
|
|
|
* we've already lost the error code, and cannot report it any
|
|
|
|
* more. So we just ignore that case instead (and hope we get
|
|
|
|
* the right error code on the flush).
|
|
|
|
*
|
|
|
|
* If the file handle is stdout, and stdout is a file, then skip the
|
|
|
|
* flush entirely since it's not needed.
|
|
|
|
*/
|
|
|
|
void maybe_flush_or_die(FILE *f, const char *desc)
|
|
|
|
{
|
|
|
|
static int skip_stdout_flush = -1;
|
|
|
|
struct stat st;
|
|
|
|
char *cp;
|
|
|
|
|
|
|
|
if (f == stdout) {
|
|
|
|
if (skip_stdout_flush < 0) {
|
2022-09-15 16:06:57 +00:00
|
|
|
/* NEEDSWORK: make this a normal Boolean */
|
2007-06-29 17:40:46 +00:00
|
|
|
cp = getenv("GIT_FLUSH");
|
|
|
|
if (cp)
|
|
|
|
skip_stdout_flush = (atoi(cp) == 0);
|
|
|
|
else if ((fstat(fileno(stdout), &st) == 0) &&
|
|
|
|
S_ISREG(st.st_mode))
|
|
|
|
skip_stdout_flush = 1;
|
|
|
|
else
|
|
|
|
skip_stdout_flush = 0;
|
|
|
|
}
|
|
|
|
if (skip_stdout_flush && !ferror(f))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fflush(f)) {
|
write_or_die: raise SIGPIPE when we get EPIPE
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>
2013-02-20 20:01:36 +00:00
|
|
|
check_pipe(errno);
|
2009-06-27 15:58:46 +00:00
|
|
|
die_errno("write failure on '%s'", desc);
|
2007-06-29 17:40:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-10 10:03:52 +00:00
|
|
|
void fprintf_or_die(FILE *f, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
ret = vfprintf(f, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
check_pipe(errno);
|
|
|
|
die_errno("write error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:43:21 +00:00
|
|
|
static int maybe_fsync(int fd)
|
2008-05-30 15:42:16 +00:00
|
|
|
{
|
2021-10-29 00:15:52 +00:00
|
|
|
if (use_fsync < 0)
|
|
|
|
use_fsync = git_env_bool("GIT_TEST_FSYNC", 1);
|
|
|
|
if (!use_fsync)
|
2022-03-10 22:43:21 +00:00
|
|
|
return 0;
|
2022-03-10 22:43:20 +00:00
|
|
|
|
|
|
|
if (fsync_method == FSYNC_METHOD_WRITEOUT_ONLY &&
|
|
|
|
git_fsync(fd, FSYNC_WRITEOUT_ONLY) >= 0)
|
2022-03-10 22:43:21 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return git_fsync(fd, FSYNC_HARDWARE_FLUSH);
|
|
|
|
}
|
2022-03-10 22:43:20 +00:00
|
|
|
|
2022-03-10 22:43:21 +00:00
|
|
|
void fsync_or_die(int fd, const char *msg)
|
|
|
|
{
|
|
|
|
if (maybe_fsync(fd) < 0)
|
2022-03-10 22:43:20 +00:00
|
|
|
die_errno("fsync error on '%s'", msg);
|
2008-05-30 15:42:16 +00:00
|
|
|
}
|
|
|
|
|
2022-03-10 22:43:21 +00:00
|
|
|
int fsync_component(enum fsync_component component, int fd)
|
|
|
|
{
|
|
|
|
if (fsync_components & component)
|
|
|
|
return maybe_fsync(fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fsync_component_or_die(enum fsync_component component, int fd, const char *msg)
|
|
|
|
{
|
|
|
|
if (fsync_components & component)
|
|
|
|
fsync_or_die(fd, msg);
|
|
|
|
}
|
|
|
|
|
2007-01-08 15:58:23 +00:00
|
|
|
void write_or_die(int fd, const void *buf, size_t count)
|
2006-08-31 06:42:11 +00:00
|
|
|
{
|
2007-01-12 04:23:00 +00:00
|
|
|
if (write_in_full(fd, buf, count) < 0) {
|
write_or_die: raise SIGPIPE when we get EPIPE
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>
2013-02-20 20:01:36 +00:00
|
|
|
check_pipe(errno);
|
2009-06-27 15:58:46 +00:00
|
|
|
die_errno("write error");
|
2007-01-08 15:57:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-01 12:54:41 +00:00
|
|
|
|
|
|
|
void fwrite_or_die(FILE *f, const void *buf, size_t count)
|
|
|
|
{
|
|
|
|
if (fwrite(buf, 1, count, f) != count)
|
|
|
|
die_errno("fwrite error");
|
|
|
|
}
|
|
|
|
|
|
|
|
void fflush_or_die(FILE *f)
|
|
|
|
{
|
|
|
|
if (fflush(f))
|
|
|
|
die_errno("fflush error");
|
|
|
|
}
|