diff --git a/include/closestream.h b/include/closestream.h index 83df1ee7d..41afbe208 100644 --- a/include/closestream.h +++ b/include/closestream.h @@ -35,11 +35,37 @@ close_stream(FILE * stream) return 0; } +static inline int +flush_standard_stream(FILE *stream) +{ + int fd; + + errno = 0; + + if (ferror(stream) != 0 || fflush(stream) != 0) + goto error; + + /* + * Calling fflush is not sufficient on some filesystems + * like e.g. NFS, which may defer the actual flush until + * close. Calling fsync would help solve this, but would + * probably result in a performance hit. Thus, we work + * around this issue by calling close on a dup'd file + * descriptor from the stream. + */ + if ((fd = fileno(stream)) < 0 || (fd = dup(fd)) < 0 || close(fd) != 0) + goto error; + + return 0; +error: + return (errno == EBADF) ? 0 : EOF; +} + /* Meant to be used atexit(close_stdout); */ static inline void close_stdout(void) { - if (stdout && close_stream(stdout) != 0 && !(errno == EPIPE)) { + if (flush_standard_stream(stdout) != 0 && !(errno == EPIPE)) { if (errno) warn(_("write error")); else @@ -47,11 +73,8 @@ close_stdout(void) _exit(CLOSE_EXIT_CODE); } - if (stderr && close_stream(stderr) != 0) + if (flush_standard_stream(stderr) != 0) _exit(CLOSE_EXIT_CODE); - - stdout = NULL; - stderr = NULL; } static inline void