1*86d7f5d3SJohn Marino /* closeout.c - close standard output
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
4*86d7f5d3SJohn Marino Foundation, Inc.
5*86d7f5d3SJohn Marino
6*86d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
7*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
8*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
9*86d7f5d3SJohn Marino any later version.
10*86d7f5d3SJohn Marino
11*86d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
12*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*86d7f5d3SJohn Marino GNU General Public License for more details.
15*86d7f5d3SJohn Marino
16*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
17*86d7f5d3SJohn Marino along with this program; if not, write to the Free Software Foundation,
18*86d7f5d3SJohn Marino Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19*86d7f5d3SJohn Marino
20*86d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
21*86d7f5d3SJohn Marino # include <config.h>
22*86d7f5d3SJohn Marino #endif
23*86d7f5d3SJohn Marino
24*86d7f5d3SJohn Marino #include "closeout.h"
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #include <stdio.h>
27*86d7f5d3SJohn Marino #include <stdbool.h>
28*86d7f5d3SJohn Marino #include <errno.h>
29*86d7f5d3SJohn Marino
30*86d7f5d3SJohn Marino #include "gettext.h"
31*86d7f5d3SJohn Marino #define _(msgid) gettext (msgid)
32*86d7f5d3SJohn Marino
33*86d7f5d3SJohn Marino #include "error.h"
34*86d7f5d3SJohn Marino #include "exitfail.h"
35*86d7f5d3SJohn Marino #include "quotearg.h"
36*86d7f5d3SJohn Marino
37*86d7f5d3SJohn Marino #if USE_UNLOCKED_IO
38*86d7f5d3SJohn Marino # include "unlocked-io.h"
39*86d7f5d3SJohn Marino #endif
40*86d7f5d3SJohn Marino
41*86d7f5d3SJohn Marino static const char *file_name;
42*86d7f5d3SJohn Marino
43*86d7f5d3SJohn Marino /* Set the file name to be reported in the event an error is detected
44*86d7f5d3SJohn Marino by close_stdout. */
45*86d7f5d3SJohn Marino void
close_stdout_set_file_name(const char * file)46*86d7f5d3SJohn Marino close_stdout_set_file_name (const char *file)
47*86d7f5d3SJohn Marino {
48*86d7f5d3SJohn Marino file_name = file;
49*86d7f5d3SJohn Marino }
50*86d7f5d3SJohn Marino
51*86d7f5d3SJohn Marino /* Close standard output, exiting with status 'exit_failure' on failure.
52*86d7f5d3SJohn Marino If a program writes *anything* to stdout, that program should close
53*86d7f5d3SJohn Marino stdout and make sure that it succeeds before exiting. Otherwise,
54*86d7f5d3SJohn Marino suppose that you go to the extreme of checking the return status
55*86d7f5d3SJohn Marino of every function that does an explicit write to stdout. The last
56*86d7f5d3SJohn Marino printf can succeed in writing to the internal stream buffer, and yet
57*86d7f5d3SJohn Marino the fclose(stdout) could still fail (due e.g., to a disk full error)
58*86d7f5d3SJohn Marino when it tries to write out that buffered data. Thus, you would be
59*86d7f5d3SJohn Marino left with an incomplete output file and the offending program would
60*86d7f5d3SJohn Marino exit successfully. Even calling fflush is not always sufficient,
61*86d7f5d3SJohn Marino since some file systems (NFS and CODA) buffer written/flushed data
62*86d7f5d3SJohn Marino until an actual close call.
63*86d7f5d3SJohn Marino
64*86d7f5d3SJohn Marino Besides, it's wasteful to check the return value from every call
65*86d7f5d3SJohn Marino that writes to stdout -- just let the internal stream state record
66*86d7f5d3SJohn Marino the failure. That's what the ferror test is checking below.
67*86d7f5d3SJohn Marino
68*86d7f5d3SJohn Marino It's important to detect such failures and exit nonzero because many
69*86d7f5d3SJohn Marino tools (most notably `make' and other build-management systems) depend
70*86d7f5d3SJohn Marino on being able to detect failure in other tools via their exit status. */
71*86d7f5d3SJohn Marino
72*86d7f5d3SJohn Marino void
close_stdout(void)73*86d7f5d3SJohn Marino close_stdout (void)
74*86d7f5d3SJohn Marino {
75*86d7f5d3SJohn Marino bool prev_fail = ferror (stdout);
76*86d7f5d3SJohn Marino bool none_pending = (0 == __fpending (stdout));
77*86d7f5d3SJohn Marino bool fclose_fail = fclose (stdout);
78*86d7f5d3SJohn Marino
79*86d7f5d3SJohn Marino if (prev_fail || fclose_fail)
80*86d7f5d3SJohn Marino {
81*86d7f5d3SJohn Marino int e = fclose_fail ? errno : 0;
82*86d7f5d3SJohn Marino char const *write_error;
83*86d7f5d3SJohn Marino
84*86d7f5d3SJohn Marino /* If ferror returned zero, no data remains to be flushed, and we'd
85*86d7f5d3SJohn Marino otherwise fail with EBADF due to a failed fclose, then assume that
86*86d7f5d3SJohn Marino it's ok to ignore the fclose failure. That can happen when a
87*86d7f5d3SJohn Marino program like cp is invoked like this `cp a b >&-' (i.e., with
88*86d7f5d3SJohn Marino stdout closed) and doesn't generate any output (hence no previous
89*86d7f5d3SJohn Marino error and nothing to be flushed). */
90*86d7f5d3SJohn Marino if (e == EBADF && !prev_fail && none_pending)
91*86d7f5d3SJohn Marino return;
92*86d7f5d3SJohn Marino
93*86d7f5d3SJohn Marino write_error = _("write error");
94*86d7f5d3SJohn Marino if (file_name)
95*86d7f5d3SJohn Marino error (exit_failure, e, "%s: %s", quotearg_colon (file_name),
96*86d7f5d3SJohn Marino write_error);
97*86d7f5d3SJohn Marino else
98*86d7f5d3SJohn Marino error (exit_failure, e, "%s", write_error);
99*86d7f5d3SJohn Marino }
100*86d7f5d3SJohn Marino }
101