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