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