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