xref: /dflybsd-src/contrib/grep/lib/closeout.c (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
195b7b453SJohn Marino /* Close standard output and standard error, exiting with a diagnostic on error.
295b7b453SJohn Marino 
3*09d4459fSDaniel Fojt    Copyright (C) 1998-2002, 2004, 2006, 2008-2020 Free Software Foundation,
495b7b453SJohn Marino    Inc.
595b7b453SJohn Marino 
695b7b453SJohn Marino    This program is free software: you can redistribute it and/or modify
795b7b453SJohn Marino    it under the terms of the GNU General Public License as published by
895b7b453SJohn Marino    the Free Software Foundation; either version 3 of the License, or
995b7b453SJohn Marino    (at your option) any later version.
1095b7b453SJohn Marino 
1195b7b453SJohn Marino    This program is distributed in the hope that it will be useful,
1295b7b453SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1395b7b453SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1495b7b453SJohn Marino    GNU General Public License for more details.
1595b7b453SJohn Marino 
1695b7b453SJohn Marino    You should have received a copy of the GNU General Public License
17*09d4459fSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1895b7b453SJohn Marino 
1995b7b453SJohn Marino #include <config.h>
2095b7b453SJohn Marino 
2195b7b453SJohn Marino #include "closeout.h"
2295b7b453SJohn Marino 
2395b7b453SJohn Marino #include <errno.h>
2495b7b453SJohn Marino #include <stdbool.h>
2595b7b453SJohn Marino #include <stdio.h>
2695b7b453SJohn Marino #include <unistd.h>
2795b7b453SJohn Marino 
2895b7b453SJohn Marino #include "gettext.h"
2995b7b453SJohn Marino #define _(msgid) gettext (msgid)
3095b7b453SJohn Marino 
3195b7b453SJohn Marino #include "close-stream.h"
3295b7b453SJohn Marino #include "error.h"
3395b7b453SJohn Marino #include "exitfail.h"
3495b7b453SJohn Marino #include "quotearg.h"
3595b7b453SJohn Marino 
36*09d4459fSDaniel Fojt #ifndef __has_feature
37*09d4459fSDaniel Fojt # define __has_feature(a) false
38*09d4459fSDaniel Fojt #endif
39*09d4459fSDaniel Fojt 
40*09d4459fSDaniel Fojt #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
41*09d4459fSDaniel Fojt enum { SANITIZE_ADDRESS = true };
42*09d4459fSDaniel Fojt #else
43*09d4459fSDaniel Fojt enum { SANITIZE_ADDRESS = false };
44*09d4459fSDaniel Fojt #endif
45*09d4459fSDaniel Fojt 
4695b7b453SJohn Marino static const char *file_name;
4795b7b453SJohn Marino 
4895b7b453SJohn Marino /* Set the file name to be reported in the event an error is detected
4995b7b453SJohn Marino    by close_stdout.  */
5095b7b453SJohn Marino void
close_stdout_set_file_name(const char * file)5195b7b453SJohn Marino close_stdout_set_file_name (const char *file)
5295b7b453SJohn Marino {
5395b7b453SJohn Marino   file_name = file;
5495b7b453SJohn Marino }
5595b7b453SJohn Marino 
5695b7b453SJohn Marino static bool ignore_EPIPE /* = false */;
5795b7b453SJohn Marino 
5895b7b453SJohn Marino /* Specify the reaction to an EPIPE error during the closing of stdout:
5995b7b453SJohn Marino      - If ignore = true, it shall be ignored.
6095b7b453SJohn Marino      - If ignore = false, it shall evoke a diagnostic, along with a nonzero
6195b7b453SJohn Marino        exit status.
6295b7b453SJohn Marino    The default is ignore = false.
6395b7b453SJohn Marino 
6495b7b453SJohn Marino    This setting matters only if the SIGPIPE signal is ignored (i.e. its
6595b7b453SJohn Marino    handler set to SIG_IGN) or blocked.  Only particular programs need to
6695b7b453SJohn Marino    temporarily ignore SIGPIPE.  If SIGPIPE is ignored or blocked because
6795b7b453SJohn Marino    it was ignored or blocked in the parent process when it created the
6895b7b453SJohn Marino    child process, it usually is a bug in the parent process: It is bad
6995b7b453SJohn Marino    practice to have SIGPIPE ignored or blocked while creating a child
7095b7b453SJohn Marino    process.
7195b7b453SJohn Marino 
7295b7b453SJohn Marino    EPIPE occurs when writing to a pipe or socket that has no readers now,
7395b7b453SJohn Marino    when SIGPIPE is ignored or blocked.
7495b7b453SJohn Marino 
7595b7b453SJohn Marino    The ignore = false setting is suitable for a scenario where it is normally
7695b7b453SJohn Marino    guaranteed that the pipe writer terminates before the pipe reader.  In
7795b7b453SJohn Marino    this case, an EPIPE is an indication of a premature termination of the
7895b7b453SJohn Marino    pipe reader and should lead to a diagnostic and a nonzero exit status.
7995b7b453SJohn Marino 
8095b7b453SJohn Marino    The ignore = true setting is suitable for a scenario where you don't know
8195b7b453SJohn Marino    ahead of time whether the pipe writer or the pipe reader will terminate
8295b7b453SJohn Marino    first.  In this case, an EPIPE is an indication that the pipe writer can
8395b7b453SJohn Marino    stop doing useless write() calls; this is what close_stdout does anyway.
8495b7b453SJohn Marino    EPIPE is part of the normal pipe/socket shutdown protocol in this case,
8595b7b453SJohn Marino    and should not lead to a diagnostic message.  */
8695b7b453SJohn Marino 
8795b7b453SJohn Marino void
close_stdout_set_ignore_EPIPE(bool ignore)8895b7b453SJohn Marino close_stdout_set_ignore_EPIPE (bool ignore)
8995b7b453SJohn Marino {
9095b7b453SJohn Marino   ignore_EPIPE = ignore;
9195b7b453SJohn Marino }
9295b7b453SJohn Marino 
9395b7b453SJohn Marino /* Close standard output.  On error, issue a diagnostic and _exit
9495b7b453SJohn Marino    with status 'exit_failure'.
9595b7b453SJohn Marino 
9695b7b453SJohn Marino    Also close standard error.  On error, _exit with status 'exit_failure'.
9795b7b453SJohn Marino 
9895b7b453SJohn Marino    Since close_stdout is commonly registered via 'atexit', POSIX
9995b7b453SJohn Marino    and the C standard both say that it should not call 'exit',
10095b7b453SJohn Marino    because the behavior is undefined if 'exit' is called more than
10195b7b453SJohn Marino    once.  So it calls '_exit' instead of 'exit'.  If close_stdout
10295b7b453SJohn Marino    is registered via atexit before other functions are registered,
10395b7b453SJohn Marino    the other functions can act before this _exit is invoked.
10495b7b453SJohn Marino 
10595b7b453SJohn Marino    Applications that use close_stdout should flush any streams
10695b7b453SJohn Marino    other than stdout and stderr before exiting, since the call to
10795b7b453SJohn Marino    _exit will bypass other buffer flushing.  Applications should
10895b7b453SJohn Marino    be flushing and closing other streams anyway, to check for I/O
10995b7b453SJohn Marino    errors.  Also, applications should not use tmpfile, since _exit
11095b7b453SJohn Marino    can bypass the removal of these files.
11195b7b453SJohn Marino 
11295b7b453SJohn Marino    It's important to detect such failures and exit nonzero because many
113cf28ed85SJohn Marino    tools (most notably 'make' and other build-management systems) depend
11495b7b453SJohn Marino    on being able to detect failure in other tools via their exit status.  */
11595b7b453SJohn Marino 
11695b7b453SJohn Marino void
close_stdout(void)11795b7b453SJohn Marino close_stdout (void)
11895b7b453SJohn Marino {
11995b7b453SJohn Marino   if (close_stream (stdout) != 0
12095b7b453SJohn Marino       && !(ignore_EPIPE && errno == EPIPE))
12195b7b453SJohn Marino     {
12295b7b453SJohn Marino       char const *write_error = _("write error");
12395b7b453SJohn Marino       if (file_name)
12495b7b453SJohn Marino         error (0, errno, "%s: %s", quotearg_colon (file_name),
12595b7b453SJohn Marino                write_error);
12695b7b453SJohn Marino       else
12795b7b453SJohn Marino         error (0, errno, "%s", write_error);
12895b7b453SJohn Marino 
12995b7b453SJohn Marino       _exit (exit_failure);
13095b7b453SJohn Marino     }
13195b7b453SJohn Marino 
132*09d4459fSDaniel Fojt   /* Close stderr only if not sanitizing, as sanitizers may report to
133*09d4459fSDaniel Fojt      stderr after this function returns.  */
134*09d4459fSDaniel Fojt   if (!SANITIZE_ADDRESS && close_stream (stderr) != 0)
13595b7b453SJohn Marino     _exit (exit_failure);
13695b7b453SJohn Marino }
137