]> git.ipfire.org Git - thirdparty/util-linux.git/blame - include/closestream.h
Merge branch 'lslogins/man-shell' of https://github.com/t-8ch/util-linux
[thirdparty/util-linux.git] / include / closestream.h
CommitLineData
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
21static inline int
22close_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
42static inline int
43flush_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;
64error:
65 return (errno == EBADF) ? 0 : EOF;
66}
67
302e423d
SK
68/* Meant to be used atexit(close_stdout); */
69static inline void
70close_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
84static inline void
85close_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
96static inline int
97fsync(int fd __attribute__((__unused__)))
98{
99 return 0;
100}
101#endif
102
103static inline int
104close_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 */