186d7f5d3SJohn Marino /* closeout.c - close standard output
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
486d7f5d3SJohn Marino Foundation, Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
786d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
886d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
986d7f5d3SJohn Marino any later version.
1086d7f5d3SJohn Marino
1186d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
1286d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1386d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1486d7f5d3SJohn Marino GNU General Public License for more details.
1586d7f5d3SJohn Marino
1686d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
1786d7f5d3SJohn Marino along with this program; if not, write to the Free Software Foundation,
1886d7f5d3SJohn Marino Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
1986d7f5d3SJohn Marino
2086d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
2186d7f5d3SJohn Marino # include <config.h>
2286d7f5d3SJohn Marino #endif
2386d7f5d3SJohn Marino
2486d7f5d3SJohn Marino #include "closeout.h"
2586d7f5d3SJohn Marino
2686d7f5d3SJohn Marino #include <stdio.h>
2786d7f5d3SJohn Marino #include <stdbool.h>
2886d7f5d3SJohn Marino #include <errno.h>
2986d7f5d3SJohn Marino
3086d7f5d3SJohn Marino #include "gettext.h"
3186d7f5d3SJohn Marino #define _(msgid) gettext (msgid)
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino #include "error.h"
3486d7f5d3SJohn Marino #include "exitfail.h"
3586d7f5d3SJohn Marino #include "quotearg.h"
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marino #if USE_UNLOCKED_IO
3886d7f5d3SJohn Marino # include "unlocked-io.h"
3986d7f5d3SJohn Marino #endif
4086d7f5d3SJohn Marino
4186d7f5d3SJohn Marino static const char *file_name;
4286d7f5d3SJohn Marino
4386d7f5d3SJohn Marino /* Set the file name to be reported in the event an error is detected
4486d7f5d3SJohn Marino by close_stdout. */
4586d7f5d3SJohn Marino void
close_stdout_set_file_name(const char * file)4686d7f5d3SJohn Marino close_stdout_set_file_name (const char *file)
4786d7f5d3SJohn Marino {
4886d7f5d3SJohn Marino file_name = file;
4986d7f5d3SJohn Marino }
5086d7f5d3SJohn Marino
5186d7f5d3SJohn Marino /* Close standard output, exiting with status 'exit_failure' on failure.
5286d7f5d3SJohn Marino If a program writes *anything* to stdout, that program should close
5386d7f5d3SJohn Marino stdout and make sure that it succeeds before exiting. Otherwise,
5486d7f5d3SJohn Marino suppose that you go to the extreme of checking the return status
5586d7f5d3SJohn Marino of every function that does an explicit write to stdout. The last
5686d7f5d3SJohn Marino printf can succeed in writing to the internal stream buffer, and yet
5786d7f5d3SJohn Marino the fclose(stdout) could still fail (due e.g., to a disk full error)
5886d7f5d3SJohn Marino when it tries to write out that buffered data. Thus, you would be
5986d7f5d3SJohn Marino left with an incomplete output file and the offending program would
6086d7f5d3SJohn Marino exit successfully. Even calling fflush is not always sufficient,
6186d7f5d3SJohn Marino since some file systems (NFS and CODA) buffer written/flushed data
6286d7f5d3SJohn Marino until an actual close call.
6386d7f5d3SJohn Marino
6486d7f5d3SJohn Marino Besides, it's wasteful to check the return value from every call
6586d7f5d3SJohn Marino that writes to stdout -- just let the internal stream state record
6686d7f5d3SJohn Marino the failure. That's what the ferror test is checking below.
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino It's important to detect such failures and exit nonzero because many
6986d7f5d3SJohn Marino tools (most notably `make' and other build-management systems) depend
7086d7f5d3SJohn Marino on being able to detect failure in other tools via their exit status. */
7186d7f5d3SJohn Marino
7286d7f5d3SJohn Marino void
close_stdout(void)7386d7f5d3SJohn Marino close_stdout (void)
7486d7f5d3SJohn Marino {
7586d7f5d3SJohn Marino bool prev_fail = ferror (stdout);
7686d7f5d3SJohn Marino bool none_pending = (0 == __fpending (stdout));
7786d7f5d3SJohn Marino bool fclose_fail = fclose (stdout);
7886d7f5d3SJohn Marino
7986d7f5d3SJohn Marino if (prev_fail || fclose_fail)
8086d7f5d3SJohn Marino {
8186d7f5d3SJohn Marino int e = fclose_fail ? errno : 0;
8286d7f5d3SJohn Marino char const *write_error;
8386d7f5d3SJohn Marino
8486d7f5d3SJohn Marino /* If ferror returned zero, no data remains to be flushed, and we'd
8586d7f5d3SJohn Marino otherwise fail with EBADF due to a failed fclose, then assume that
8686d7f5d3SJohn Marino it's ok to ignore the fclose failure. That can happen when a
8786d7f5d3SJohn Marino program like cp is invoked like this `cp a b >&-' (i.e., with
8886d7f5d3SJohn Marino stdout closed) and doesn't generate any output (hence no previous
8986d7f5d3SJohn Marino error and nothing to be flushed). */
9086d7f5d3SJohn Marino if (e == EBADF && !prev_fail && none_pending)
9186d7f5d3SJohn Marino return;
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino write_error = _("write error");
9486d7f5d3SJohn Marino if (file_name)
9586d7f5d3SJohn Marino error (exit_failure, e, "%s: %s", quotearg_colon (file_name),
9686d7f5d3SJohn Marino write_error);
9786d7f5d3SJohn Marino else
9886d7f5d3SJohn Marino error (exit_failure, e, "%s", write_error);
9986d7f5d3SJohn Marino }
10086d7f5d3SJohn Marino }
101