X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fcloseout.c;h=18a8912dfdbfd16b06e19a5f2ab40bf0a9a8440c;hb=2988c8c21303fdadb3a9efe321870d96f6bdc668;hp=e4093fbd5f9278968fd97aa9eef0f72de169d3fa;hpb=0632e115747ff96e93330c88f536d7354a7ce507;p=gnulib.git diff --git a/lib/closeout.c b/lib/closeout.c index e4093fbd5..18a8912df 100644 --- a/lib/closeout.c +++ b/lib/closeout.c @@ -1,12 +1,12 @@ -/* Close standard output, exiting with a diagnostic on error. +/* Close standard output and standard error, exiting with a diagnostic on error. - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 Free - Software Foundation, Inc. + Copyright (C) 1998-2002, 2004, 2006, 2008-2010 Free Software Foundation, + Inc. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,14 +14,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include #include "closeout.h" #include +#include #include #include @@ -43,9 +43,48 @@ close_stdout_set_file_name (const char *file) file_name = file; } +static bool ignore_EPIPE /* = false */; + +/* Specify the reaction to an EPIPE error during the closing of stdout: + - If ignore = true, it shall be ignored. + - If ignore = false, it shall evoke a diagnostic, along with a nonzero + exit status. + The default is ignore = false. + + This setting matters only if the SIGPIPE signal is ignored (i.e. its + handler set to SIG_IGN) or blocked. Only particular programs need to + temporarily ignore SIGPIPE. If SIGPIPE is ignored or blocked because + it was ignored or blocked in the parent process when it created the + child process, it usually is a bug in the parent process: It is bad + practice to have SIGPIPE ignored or blocked while creating a child + process. + + EPIPE occurs when writing to a pipe or socket that has no readers now, + when SIGPIPE is ignored or blocked. + + The ignore = false setting is suitable for a scenario where it is normally + guaranteed that the pipe writer terminates before the pipe reader. In + this case, an EPIPE is an indication of a premature termination of the + pipe reader and should lead to a diagnostic and a nonzero exit status. + + The ignore = true setting is suitable for a scenario where you don't know + ahead of time whether the pipe writer or the pipe reader will terminate + first. In this case, an EPIPE is an indication that the pipe writer can + stop doing useless write() calls; this is what close_stdout does anyway. + EPIPE is part of the normal pipe/socket shutdown protocol in this case, + and should not lead to a diagnostic message. */ + +void +close_stdout_set_ignore_EPIPE (bool ignore) +{ + ignore_EPIPE = ignore; +} + /* Close standard output. On error, issue a diagnostic and _exit with status 'exit_failure'. + Also close standard error. On error, _exit with status 'exit_failure'. + Since close_stdout is commonly registered via 'atexit', POSIX and the C standard both say that it should not call 'exit', because the behavior is undefined if 'exit' is called more than @@ -67,15 +106,19 @@ close_stdout_set_file_name (const char *file) void close_stdout (void) { - if (close_stream (stdout) != 0) + if (close_stream (stdout) != 0 + && !(ignore_EPIPE && errno == EPIPE)) { char const *write_error = _("write error"); if (file_name) - error (0, errno, "%s: %s", quotearg_colon (file_name), - write_error); + error (0, errno, "%s: %s", quotearg_colon (file_name), + write_error); else - error (0, errno, "%s", write_error); + error (0, errno, "%s", write_error); _exit (exit_failure); } + + if (close_stream (stderr) != 0) + _exit (exit_failure); }