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