1 /* Close standard output and standard error, exiting with a diagnostic on error. 2 3 Copyright (C) 1998-2002, 2004, 2006, 2008-2021 Free Software Foundation, 4 Inc. 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 18 19 #include <config.h> 20 21 #include "closeout.h" 22 23 #include <errno.h> 24 #include <stdbool.h> 25 #include <stdio.h> 26 #include <unistd.h> 27 28 #include "gettext.h" 29 #define _(msgid) gettext (msgid) 30 31 #include "close-stream.h" 32 #include "error.h" 33 #include "exitfail.h" 34 #include "quotearg.h" 35 36 #ifndef __has_feature 37 # define __has_feature(a) false 38 #endif 39 40 #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer) 41 enum { SANITIZE_ADDRESS = true }; 42 #else 43 enum { SANITIZE_ADDRESS = false }; 44 #endif 45 46 static const char *file_name; 47 48 /* Set the file name to be reported in the event an error is detected 49 by close_stdout. */ 50 void 51 close_stdout_set_file_name (const char *file) /* */ 52 { 53 file_name = file; 54 } 55 56 static bool ignore_EPIPE /* = false */; 57 58 /* Specify the reaction to an EPIPE error during the closing of stdout: 59 - If ignore = true, it shall be ignored. 60 - If ignore = false, it shall evoke a diagnostic, along with a nonzero 61 exit status. 62 The default is ignore = false. 63 64 This setting matters only if the SIGPIPE signal is ignored (i.e. its 65 handler set to SIG_IGN) or blocked. Only particular programs need to 66 temporarily ignore SIGPIPE. If SIGPIPE is ignored or blocked because 67 it was ignored or blocked in the parent process when it created the 68 child process, it usually is a bug in the parent process: It is bad 69 practice to have SIGPIPE ignored or blocked while creating a child 70 process. 71 72 EPIPE occurs when writing to a pipe or socket that has no readers now, 73 when SIGPIPE is ignored or blocked. 74 75 The ignore = false setting is suitable for a scenario where it is normally 76 guaranteed that the pipe writer terminates before the pipe reader. In 77 this case, an EPIPE is an indication of a premature termination of the 78 pipe reader and should lead to a diagnostic and a nonzero exit status. 79 80 The ignore = true setting is suitable for a scenario where you don't know 81 ahead of time whether the pipe writer or the pipe reader will terminate 82 first. In this case, an EPIPE is an indication that the pipe writer can 83 stop doing useless write() calls; this is what close_stdout does anyway. 84 EPIPE is part of the normal pipe/socket shutdown protocol in this case, 85 and should not lead to a diagnostic message. */ 86 87 void 88 close_stdout_set_ignore_EPIPE (bool ignore) /* */ 89 { 90 ignore_EPIPE = ignore; 91 } 92 93 /* Close standard output. On error, issue a diagnostic and _exit 94 with status 'exit_failure'. 95 96 Also close standard error. On error, _exit with status 'exit_failure'. 97 98 Since close_stdout is commonly registered via 'atexit', POSIX 99 and the C standard both say that it should not call 'exit', 100 because the behavior is undefined if 'exit' is called more than 101 once. So it calls '_exit' instead of 'exit'. If close_stdout 102 is registered via atexit before other functions are registered, 103 the other functions can act before this _exit is invoked. 104 105 Applications that use close_stdout should flush any streams 106 other than stdout and stderr before exiting, since the call to 107 _exit will bypass other buffer flushing. Applications should 108 be flushing and closing other streams anyway, to check for I/O 109 errors. Also, applications should not use tmpfile, since _exit 110 can bypass the removal of these files. 111 112 It's important to detect such failures and exit nonzero because many 113 tools (most notably 'make' and other build-management systems) depend 114 on being able to detect failure in other tools via their exit status. */ 115 116 void 117 close_stdout (void) /* */ 118 { 119 if (close_stream (stdout) != 0 120 && !(ignore_EPIPE && errno == EPIPE)) 121 { 122 char const *write_error = _("write error"); 123 if (file_name) 124 error (0, errno, "%s: %s", quotearg_colon (file_name), 125 write_error); 126 else 127 error (0, errno, "%s", write_error); 128 129 _exit (exit_failure); 130 } 131 132 /* Close stderr only if not sanitizing, as sanitizers may report to 133 stderr after this function returns. */ 134 if (!SANITIZE_ADDRESS && close_stream (stderr) != 0) 135 _exit (exit_failure); 136 }