Coverage Report

Created: 2025-06-13 06:36

/src/util-linux/include/closestream.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * No copyright is claimed.  This code is in the public domain; do with
3
 * it what you wish.
4
 */
5
#ifndef UTIL_LINUX_CLOSESTREAM_H
6
#define UTIL_LINUX_CLOSESTREAM_H
7
8
#include <stdio.h>
9
#ifdef HAVE_STDIO_EXT_H
10
#include <stdio_ext.h>
11
#endif
12
#include <unistd.h>
13
14
#include "c.h"
15
#include "nls.h"
16
17
#ifndef CLOSE_EXIT_CODE
18
# define CLOSE_EXIT_CODE EXIT_FAILURE
19
#endif
20
21
static inline int
22
close_stream(FILE * stream)
23
0
{
24
0
#ifdef HAVE___FPENDING
25
0
  const int some_pending = (__fpending(stream) != 0);
26
0
#endif
27
0
  const int prev_fail = (ferror(stream) != 0);
28
0
  const int fclose_fail = (fclose(stream) != 0);
29
30
0
  if (prev_fail || (fclose_fail && (
31
0
#ifdef HAVE___FPENDING
32
0
            some_pending ||
33
0
#endif
34
0
            errno != EBADF))) {
35
0
    if (!fclose_fail && !(errno == EPIPE))
36
0
      errno = 0;
37
0
    return EOF;
38
0
  }
39
0
  return 0;
40
0
}
41
42
static inline int
43
flush_standard_stream(FILE *stream)
44
0
{
45
0
  int fd;
46
0
47
0
  errno = 0;
48
0
49
0
  if (ferror(stream) != 0 || fflush(stream) != 0)
50
0
    goto error;
51
0
52
0
  /*
53
0
   * Calling fflush is not sufficient on some filesystems
54
0
   * like e.g. NFS, which may defer the actual flush until
55
0
   * close. Calling fsync would help solve this, but would
56
0
   * probably result in a performance hit. Thus, we work
57
0
   * around this issue by calling close on a dup'd file
58
0
   * descriptor from the stream.
59
0
   */
60
0
  if ((fd = fileno(stream)) < 0 || (fd = dup(fd)) < 0 || close(fd) != 0)
61
0
    goto error;
62
0
63
0
  return 0;
64
0
error:
65
0
  return (errno == EBADF) ? 0 : EOF;
66
0
}
67
68
/* Meant to be used atexit(close_stdout); */
69
static inline void
70
close_stdout(void)
71
0
{
72
0
  if (flush_standard_stream(stdout) != 0 && !(errno == EPIPE)) {
73
0
    if (errno)
74
0
      warn(_("write error"));
75
0
    else
76
0
      warnx(_("write error"));
77
0
    _exit(CLOSE_EXIT_CODE);
78
0
  }
79
0
80
0
  if (flush_standard_stream(stderr) != 0)
81
0
    _exit(CLOSE_EXIT_CODE);
82
0
}
83
84
static inline void
85
close_stdout_atexit(void)
86
0
{
87
0
  /*
88
0
   * Note that close stdout at exit disables ASAN to report memory leaks
89
0
   */
90
0
#if !HAS_FEATURE_ADDRESS_SANITIZER
91
0
  atexit(close_stdout);
92
0
#endif
93
0
}
94
95
#ifndef HAVE_FSYNC
96
static inline int
97
fsync(int fd __attribute__((__unused__)))
98
{
99
  return 0;
100
}
101
#endif
102
103
static inline int
104
close_fd(int fd)
105
0
{
106
0
  const int fsync_fail = (fsync(fd) != 0);
107
0
  const int close_fail = (close(fd) != 0);
108
0
109
0
  if (fsync_fail || close_fail)
110
0
    return EOF;
111
0
  return 0;
112
0
}
113
114
#endif /* UTIL_LINUX_CLOSESTREAM_H */