Thread (38 messages) 38 messages, 5 authors, 2021-02-05

Re: git fails with a broken pipe when one quits the pager

From: Ævar Arnfjörð Bjarmason <hidden>
Date: 2021-02-04 00:15:11

On Wed, Feb 03 2021, Vincent Lefevre wrote:
On 2021-02-01 16:44:24 +0100, Ævar Arnfjörð Bjarmason wrote:
quoted
And then whether it makes sense to ignore SIGPIPE for all users, or
e.g. if it's some opt-in setting in some situations that users might
want to turn on because they're aware of how their pager behaves and
want to work around some zsh mode.
AFAIK, SIGPIPE exists for the following reason. Most programs that
generate output are not written to specifically handle pipes. So,
if SIGPIPE did not exist, there would be 2 kinds of behavior:
  1. The program doesn't check for errors, and still outputs data,
     wasting time and resources as output will be ignored.
  2. The program sees that the write() failed and terminates with
     an error message. However, in most cases, such a failure is
     not an error: the consumer has terminated either because it
     no longer needs any input (e.g. with the "head" utility or a
     pager), or because it has terminated abnormally, in which case
     the real error is on the side of the consumer. So, the error
     message from the LHS of the pipe would be annoying.

SIGPIPE solves this issue: the program is simply killed with SIGPIPE.
In a shell, one gets a non-zero exit code (128 + 13) due to the
signal, but as being on the left-hand side of the pipe, such a
non-zero exit code is normally not reported, so that this will not
annoy the user.

Note 1: Non-zero exit codes from right-hand side are not reported
either by most shells, but zsh can report them, and this is very
useful for developers, as programs may fail with a non-zero exit
code but without an error message. (Reports may also be done by
looking at the standard $? in some hook.)

Note 2: Failures on the left-hand side are less interesting in practice
and generally ignored, at least for commands run in interactive shells.
For scripts, there are various (non-simple) ways to handle them.

Now, I think that in the case (like Git) a program creates a pipe,
it should use its knowledge to handle SIGPIPE / EPIPE. Either this
is regarded as an error because the full output is *always expected*
to be read, in which case there should be an error message in addition
to the usual non-zero exist status (not necessarily 141), or this is
regarded as OK (if there is a real failure, this is on the side of
the consumer). In the case of Git, the consumer is documented to be
a pager, which obviously may not read the full output (e.g. for the
GCC repository, "git log" returns more than 3 million lines, back to
the year 1988, while one is generally interested in the latest changes
only). If the user wants to pipe to something else, he can always use
an explicit pipe.
SIGPIPE exists because *nix systems are composable, so you can make
something useful by stringing together unrelated programs via files and
pipes, and with exit codes and signal mostly everyone's happy.

I follow what you're saying right until the point of arguing that
because either your shell or POSIX shells in general have decided to
either be sloppy or overzelous in how they show you some
information. That we should use their behavior as a guide in
pro-actively suppressing our own exit code.

And that's not because I think (to the tune of Monty Python...) that
every exit code is sacret. It's because when we invoke a pager handing
it data is *the* thing we're doing. If we can fully hand it over, great,
if not, let's tell the user with the appropriate exit code.

Yeah it's annoying with zsh's PRINT_EXIT_VALUE, but the same is true of
POSIX "set -e". Not every shell option is meant for general use. The
shell is very forgiving of things like pipe failures by default for a
reason.

But "connected to a terminal" (isatty(1)) and "invoked by Vincent's zsh
instance" aren't the same thing. And I think it makes sense to be
conservative in preserving exit codes.

In the early days of git complaining about "Broken pipe" in the exact
same scenario was the default behavior of bash's overzelous reporting,
as you can read about starting here:
https://lore.kernel.org/git/?q=%22Broken+pipe%22+bash&o=-1

AFAICT that changed by default in bash 3.1, released in 2005-12-08. It
was a FAQ in the early days, now nobody cares.

Have you reported this as a bug to zsh? I think it's likely that the
motivation for wanting this squashed in git is going to be as transitory
as bash's once-default verbosity was.

I also tested "hg log", it behaves the same way, although interestingly
they cast SIGPIPE to 255 in their exit code.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help