summaryrefslogtreecommitdiff
path: root/lib/closeout.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2004-11-15 17:45:32 +0000
committerJim Meyering <jim@meyering.net>2004-11-15 17:45:32 +0000
commit12797e006016ec69a5c0760999d5cd7c2a372b54 (patch)
treeb9ab965752bc2d863783c4485963155780a8d04c /lib/closeout.c
parentafdbddd5557c899bbb260bdd61f4bfde0f8ac3b6 (diff)
downloadgnulib-12797e006016ec69a5c0760999d5cd7c2a372b54.tar.gz
Include "__fpending.h" once again.
Include <stdbool.h>. (close_stdout): Don't fail just because stdout was closed initially, since some programs don't write to stdout in the normal course of operation (other than --version and --help), and we don't want this function to make e.g. `touch file >&-' fail. But do fail if it was closed and someone has tried to write to it. E.g., `printf foo >&-' must fail.
Diffstat (limited to 'lib/closeout.c')
-rw-r--r--lib/closeout.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/lib/closeout.c b/lib/closeout.c
index b0eed90eae..14aa1d3624 100644
--- a/lib/closeout.c
+++ b/lib/closeout.c
@@ -24,6 +24,7 @@
#include "closeout.h"
#include <stdio.h>
+#include <stdbool.h>
#include <errno.h>
#include "gettext.h"
@@ -32,6 +33,7 @@
#include "error.h"
#include "exitfail.h"
#include "quotearg.h"
+#include "__fpending.h"
#if USE_UNLOCKED_IO
# include "unlocked-io.h"
@@ -71,14 +73,25 @@ close_stdout_set_file_name (const char *file)
void
close_stdout (void)
{
- int e = ferror (stdout) ? 0 : -1;
+ bool prev_fail = ferror (stdout);
+ bool none_pending = (0 == __fpending (stdout));
+ bool fclose_fail = fclose (stdout);
- if (fclose (stdout) != 0)
- e = errno;
-
- if (0 <= e)
+ if (prev_fail || fclose_fail)
{
- char const *write_error = _("write error");
+ int e = fclose_fail ? errno : 0;
+ char const *write_error;
+
+ /* If ferror returned zero, no data remains to be flushed, and we'd
+ otherwise fail with EBADF due to a failed fclose, then assume that
+ it's ok to ignore the fclose failure. That can happen when a
+ program like cp is invoked like this `cp a b >&-' (i.e., with
+ stdout closed) and doesn't generate any output (hence no previous
+ error and nothing to be flushed). */
+ if (e == EBADF && !prev_fail && none_pending)
+ return;
+
+ write_error = _("write error");
if (file_name)
error (exit_failure, e, "%s: %s", quotearg_colon (file_name),
write_error);