]>
Commit | Line | Data |
---|---|---|
302e423d SK |
1 | #ifndef UTIL_LINUX_CLOSESTREAM_H |
2 | #define UTIL_LINUX_CLOSESTREAM_H | |
3 | ||
4 | #include <stdio.h> | |
78288764 | 5 | #ifdef HAVE_STDIO_EXT_H |
302e423d | 6 | #include <stdio_ext.h> |
78288764 | 7 | #endif |
302e423d SK |
8 | #include <unistd.h> |
9 | ||
10 | #include "c.h" | |
11 | #include "nls.h" | |
12 | ||
090d8c76 KZ |
13 | #ifndef CLOSE_EXIT_CODE |
14 | # define CLOSE_EXIT_CODE EXIT_FAILURE | |
15 | #endif | |
16 | ||
302e423d SK |
17 | static inline int |
18 | close_stream(FILE * stream) | |
19 | { | |
b211467f | 20 | #ifdef HAVE___FPENDING |
302e423d | 21 | const int some_pending = (__fpending(stream) != 0); |
b211467f | 22 | #endif |
302e423d SK |
23 | const int prev_fail = (ferror(stream) != 0); |
24 | const int fclose_fail = (fclose(stream) != 0); | |
422f93bf | 25 | |
b211467f SK |
26 | if (prev_fail || (fclose_fail && ( |
27 | #ifdef HAVE___FPENDING | |
28 | some_pending || | |
29 | #endif | |
30 | errno != EBADF))) { | |
422f93bf | 31 | if (!fclose_fail && !(errno == EPIPE)) |
302e423d SK |
32 | errno = 0; |
33 | return EOF; | |
34 | } | |
35 | return 0; | |
36 | } | |
37 | ||
530220b6 PS |
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 | ||
302e423d SK |
64 | /* Meant to be used atexit(close_stdout); */ |
65 | static inline void | |
66 | close_stdout(void) | |
67 | { | |
530220b6 | 68 | if (flush_standard_stream(stdout) != 0 && !(errno == EPIPE)) { |
302e423d SK |
69 | if (errno) |
70 | warn(_("write error")); | |
71 | else | |
72 | warnx(_("write error")); | |
090d8c76 | 73 | _exit(CLOSE_EXIT_CODE); |
302e423d SK |
74 | } |
75 | ||
530220b6 | 76 | if (flush_standard_stream(stderr) != 0) |
090d8c76 | 77 | _exit(CLOSE_EXIT_CODE); |
302e423d SK |
78 | } |
79 | ||
31c66833 KZ |
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 | */ | |
084365f1 | 86 | #if !defined(__SANITIZE_ADDRESS__) |
31c66833 KZ |
87 | atexit(close_stdout); |
88 | #endif | |
89 | } | |
90 | ||
f416563b SK |
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 | ||
302e423d | 110 | #endif /* UTIL_LINUX_CLOSESTREAM_H */ |