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 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