bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: EPIPE in standard utils ([issue41])


From: Tom Lord
Subject: Re: EPIPE in standard utils ([issue41])
Date: Mon, 3 Mar 2003 17:04:24 -0800 (PST)



       (2) doesn't seem correct to me.  A program that does not do
       anything special will get a SIGPIPE signal when it writes to a
       pipe with no reader, and accordingly will die with a nonzero
       status.  We can't reasonably expect every program to catch
       SIGPIPE and do something non-default in this case.  So we have
       to expect that an ordinary program will exit with nonzero
       status if it writes to a pipe that has no reader.


Well, I'm not so sure about that but my immediate concern is with (1)
(the error message) not (2) (the exit status), so, lemme defer that
argument for a minute:

     I agree that "sed" shouldn't print anything here, since it's an
     ordinary utility.  But are you sure it's "sed" that is printing the
     message, and not the shell that invokes "sed"?  Some shells have that
     problem.

The particular error message that prompted me to write is

    sed: Couldn't close {standard output}: Broken pipe

which appears to come from `ck_fclose' in `sed/utils.c' of GNU sed
(the user is using `--version' 3.02 and I'm looking at source for
sed-3.02.80).  I _vaguely_ recall getting similar reports about other
GNU utils besides sed.

Perhaps I'm missing it -- but this version of sed doesn't appear to
ignore SIGPIPE.  Therefore, a `write(2)' (as when buffer flushing
during an `fclose') to a readerless pipe will generate _both_ an EPIPE
errno _and_ a SIGPIPE.

I wonder if there isn't a race condition here: the error return being
processed before the signal is delivered.  Certainly the return has to
occur before the signal is delivered or else you'd expect the system
call to return an EINTR -- so if soon after the return you spew on
stderr, you get the losing behavior described here.   I admit I'm not
too clear on what would defer a signal delivery beyond a subsequent
`write(2)' to stderr -- but it's not unimaginable by any means.

That brings us back to your argument about (2).  While killing the
process after a SIGPIPE is the default behavior, I'd argue that it is
not a default standard utilities should adopt.  Since they have to
treat EPIPE specially _anyway_ -- they ought to uniformly ignore
SIGPIPE.  In other words, I regard the default process-terminating
response to SIGPIPE as a convenience, not a recommended behavior for
standard utils.  It might be compared to SIGFPE in that regard -- you
get this signal (SIGPIPE) when you declare (by not ignoring SIGPIPE)
that you don't think your program will ever write to a readerless
pipe, but then it happened anyway.  A complete program that expects to
write to potentially readerless pipes should ignore SIGPIPE, and
handle EPIPE (and for standard shell utils, handle it by exitting
cleanly) (or it might handle SIGPIPE itself, of course).


         (1) is not the default behavior, since a program that is
         killed by SIGPIPE doesn't write anything to stderr.

Yes, but, there are no timing guarantees about when SIGPIPE is
delivered.   Programs therefore have to deal with EPIPE but, sed, for
one, deals with EPIPE incorrectly by not dealing with it specially.

        However, it may be too much to prohibit (1) entirely; there
        may be some applications for which it makes more sense to
        print an error message.

I'd be happy to have a convention that applied only to the standard
POSIX util replacements, plus new programs that are meant to work
similarly. 


        For "(sed A && B) | head -n1", it's common to not want to
        execute B if "sed A" fails due to a pipe error.  So it makes
        sense for "sed" to exit with nonzero status if it has a pipe
        error.

I disagree.   I think that, at most, it's an unattended corner case
and that few people have any such expectation.

Where `B' is a standard util, the behavior I've proscribed (exiting on
EPIPE, ignoring SIGPIPE) works perfectly well for that shell idiom.

-t




reply via email to

[Prev in Thread] Current Thread [Next in Thread]