195b7b453SJohn Marino /* Close a stream, with nicer error checking than fclose's.
295b7b453SJohn Marino
3*09d4459fSDaniel Fojt Copyright (C) 1998-2002, 2004, 2006-2020 Free Software Foundation, Inc.
495b7b453SJohn Marino
595b7b453SJohn Marino This program is free software: you can redistribute it and/or modify
695b7b453SJohn Marino it under the terms of the GNU General Public License as published by
795b7b453SJohn Marino the Free Software Foundation; either version 3 of the License, or
895b7b453SJohn Marino (at your option) any later version.
995b7b453SJohn Marino
1095b7b453SJohn Marino This program is distributed in the hope that it will be useful,
1195b7b453SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1295b7b453SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1395b7b453SJohn Marino GNU General Public License for more details.
1495b7b453SJohn Marino
1595b7b453SJohn Marino You should have received a copy of the GNU General Public License
16*09d4459fSDaniel Fojt along with this program. If not, see <https://www.gnu.org/licenses/>. */
1795b7b453SJohn Marino
1895b7b453SJohn Marino #include <config.h>
1995b7b453SJohn Marino
2095b7b453SJohn Marino #include "close-stream.h"
2195b7b453SJohn Marino
2295b7b453SJohn Marino #include <errno.h>
2395b7b453SJohn Marino #include <stdbool.h>
2495b7b453SJohn Marino
2595b7b453SJohn Marino #include "fpending.h"
2695b7b453SJohn Marino
2795b7b453SJohn Marino #if USE_UNLOCKED_IO
2895b7b453SJohn Marino # include "unlocked-io.h"
2995b7b453SJohn Marino #endif
3095b7b453SJohn Marino
3195b7b453SJohn Marino /* Close STREAM. Return 0 if successful, EOF (setting errno)
3295b7b453SJohn Marino otherwise. A failure might set errno to 0 if the error number
3395b7b453SJohn Marino cannot be determined.
3495b7b453SJohn Marino
3595b7b453SJohn Marino A failure with errno set to EPIPE may or may not indicate an error
3695b7b453SJohn Marino situation worth signaling to the user. See the documentation of the
3795b7b453SJohn Marino close_stdout_set_ignore_EPIPE function for details.
3895b7b453SJohn Marino
3995b7b453SJohn Marino If a program writes *anything* to STREAM, that program should close
4095b7b453SJohn Marino STREAM and make sure that it succeeds before exiting. Otherwise,
4195b7b453SJohn Marino suppose that you go to the extreme of checking the return status
4295b7b453SJohn Marino of every function that does an explicit write to STREAM. The last
4395b7b453SJohn Marino printf can succeed in writing to the internal stream buffer, and yet
4495b7b453SJohn Marino the fclose(STREAM) could still fail (due e.g., to a disk full error)
4595b7b453SJohn Marino when it tries to write out that buffered data. Thus, you would be
4695b7b453SJohn Marino left with an incomplete output file and the offending program would
4795b7b453SJohn Marino exit successfully. Even calling fflush is not always sufficient,
4895b7b453SJohn Marino since some file systems (NFS and CODA) buffer written/flushed data
4995b7b453SJohn Marino until an actual close call.
5095b7b453SJohn Marino
5195b7b453SJohn Marino Besides, it's wasteful to check the return value from every call
5295b7b453SJohn Marino that writes to STREAM -- just let the internal stream state record
5395b7b453SJohn Marino the failure. That's what the ferror test is checking below. */
5495b7b453SJohn Marino
5595b7b453SJohn Marino int
close_stream(FILE * stream)5695b7b453SJohn Marino close_stream (FILE *stream)
5795b7b453SJohn Marino {
5895b7b453SJohn Marino const bool some_pending = (__fpending (stream) != 0);
5995b7b453SJohn Marino const bool prev_fail = (ferror (stream) != 0);
6095b7b453SJohn Marino const bool fclose_fail = (fclose (stream) != 0);
6195b7b453SJohn Marino
6295b7b453SJohn Marino /* Return an error indication if there was a previous failure or if
6395b7b453SJohn Marino fclose failed, with one exception: ignore an fclose failure if
6495b7b453SJohn Marino there was no previous error, no data remains to be flushed, and
6595b7b453SJohn Marino fclose failed with EBADF. That can happen when a program like cp
66cf28ed85SJohn Marino is invoked like this 'cp a b >&-' (i.e., with standard output
6795b7b453SJohn Marino closed) and doesn't generate any output (hence no previous error
6895b7b453SJohn Marino and nothing to be flushed). */
6995b7b453SJohn Marino
7095b7b453SJohn Marino if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
7195b7b453SJohn Marino {
7295b7b453SJohn Marino if (! fclose_fail)
7395b7b453SJohn Marino errno = 0;
7495b7b453SJohn Marino return EOF;
7595b7b453SJohn Marino }
7695b7b453SJohn Marino
7795b7b453SJohn Marino return 0;
7895b7b453SJohn Marino }
79