ust-fd: Add close_range declaration
[lttng-ust.git] / src / lib / lttng-ust-fd / lttng-ust-fd.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 */
6
7 #define _LGPL_SOURCE
8 #include <limits.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <dlfcn.h>
13 #include <errno.h>
14
15 #include <lttng/ust-common.h>
16
17 #include "common/macros.h"
18 #include "common/ust-fd.h"
19
20 #define LTTNG_UST_DLSYM_FAILED_PTR 0x1
21
22 static int (*__lttng_ust_fd_plibc_close)(int fd) = NULL;
23 static int (*__lttng_ust_fd_plibc_fclose)(FILE *stream) = NULL;
24 static int (*__lttng_ust_fd_plibc_close_range)(unsigned int first,
25 unsigned int last, int flags) = NULL;
26
27 /*
28 * Use dlsym to find the original libc close() symbol and store it in
29 * __lttng_ust_fd_plibc_close.
30 */
31 static
32 void *_lttng_ust_fd_init_plibc_close(void)
33 {
34 if (__lttng_ust_fd_plibc_close == NULL) {
35 __lttng_ust_fd_plibc_close = dlsym(RTLD_NEXT, "close");
36
37 if (__lttng_ust_fd_plibc_close == NULL) {
38 __lttng_ust_fd_plibc_close = (void *) LTTNG_UST_DLSYM_FAILED_PTR;
39 fprintf(stderr, "%s\n", dlerror());
40 }
41 }
42
43 return __lttng_ust_fd_plibc_close;
44 }
45
46 /*
47 * Use dlsym to find the original libc fclose() symbol and store it in
48 * __lttng_ust_fd_plibc_fclose.
49 */
50 static
51 void *_lttng_ust_fd_init_plibc_fclose(void)
52 {
53 if (__lttng_ust_fd_plibc_fclose == NULL) {
54 __lttng_ust_fd_plibc_fclose = dlsym(RTLD_NEXT, "fclose");
55
56 if (__lttng_ust_fd_plibc_fclose == NULL) {
57 __lttng_ust_fd_plibc_fclose = (void *) LTTNG_UST_DLSYM_FAILED_PTR;
58 fprintf(stderr, "%s\n", dlerror());
59 }
60 }
61
62 return __lttng_ust_fd_plibc_fclose;
63 }
64
65 /*
66 * Use dlsym to find the original libc close_range() symbol and store it
67 * in __lttng_ust_fd_plibc_close_range. The close_range symbol only
68 * appears in glibc 2.34, so it is considered optional.
69 */
70 static
71 void *_lttng_ust_fd_init_plibc_close_range(void)
72 {
73 if (__lttng_ust_fd_plibc_close_range == NULL) {
74 __lttng_ust_fd_plibc_close_range = dlsym(RTLD_NEXT, "close_range");
75
76 if (__lttng_ust_fd_plibc_close_range == NULL)
77 __lttng_ust_fd_plibc_close_range = (void *) LTTNG_UST_DLSYM_FAILED_PTR;
78 }
79
80 return __lttng_ust_fd_plibc_close_range;
81 }
82
83 static
84 void _lttng_ust_fd_ctor(void)
85 __attribute__((constructor));
86 static
87 void _lttng_ust_fd_ctor(void)
88 {
89 lttng_ust_common_ctor();
90
91 /*
92 * Initialize the function pointers to the original libc symbols in the
93 * constructor since close() has to stay async-signal-safe and as such,
94 * we can't call dlsym() in the override functions.
95 */
96 (void) _lttng_ust_fd_init_plibc_close();
97 (void) _lttng_ust_fd_init_plibc_fclose();
98 (void) _lttng_ust_fd_init_plibc_close_range();
99 }
100
101 /*
102 * Override the libc close() symbol with our own, allowing applications to
103 * close arbitrary file descriptors. If the fd is owned by lttng-ust, return
104 * -1, errno=EBADF instead of closing it.
105 *
106 * If dlsym failed to find the original libc close() symbol, return -1,
107 * errno=ENOSYS.
108 *
109 * There is a short window before the library constructor has executed where
110 * this wrapper could call dlsym() and thus not be async-signal-safe.
111 */
112 int close(int fd)
113 {
114 /*
115 * We can't retry dlsym here since close is async-signal-safe.
116 */
117 if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
118 errno = ENOSYS;
119 return -1;
120 }
121
122 return lttng_ust_safe_close_fd(fd, __lttng_ust_fd_plibc_close);
123 }
124
125 /*
126 * Override the libc fclose() symbol with our own, allowing applications to
127 * close arbitrary streams. If the fd is owned by lttng-ust, return -1,
128 * errno=EBADF instead of closing it.
129 *
130 * If dlsym failed to find the original libc close() symbol, return -1,
131 * errno=ENOSYS.
132 *
133 * There is a short window before the library constructor has executed where
134 * this wrapper could call dlsym() and thus not be async-signal-safe.
135 *
136 * Note: fcloseall() is not an issue because it closes only the streams it
137 * knows about, which differs from the problems caused by gnulib
138 * close_stdout(), which does an explicit fclose(stdout).
139 */
140 int fclose(FILE *stream)
141 {
142 if (_lttng_ust_fd_init_plibc_fclose() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
143 errno = ENOSYS;
144 return -1;
145 }
146
147 return lttng_ust_safe_fclose_stream(stream,
148 __lttng_ust_fd_plibc_fclose);
149 }
150
151 /* Old libc headers don't contain a close_range() declaration. */
152 int close_range(unsigned int first, unsigned int last, int flags);
153
154 /*
155 * Override the libc close_range() symbol with our own, allowing
156 * applications to close arbitrary file descriptors. If the fd is owned
157 * by lttng-ust, return -1, errno=EBADF instead of closing it.
158 *
159 * If dlsym failed to find the original libc close_range() symbol,
160 * return -1, errno=ENOSYS.
161 *
162 * There is a short window before the library constructor has executed where
163 * this wrapper could call dlsym() and thus not be async-signal-safe.
164 */
165 int close_range(unsigned int first, unsigned int last, int flags)
166 {
167 /*
168 * We can't retry dlsym here since close is async-signal-safe.
169 */
170 if (_lttng_ust_fd_init_plibc_close_range() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
171 errno = ENOSYS;
172 return -1;
173 }
174
175 return lttng_ust_safe_close_range_fd(first, last, flags, __lttng_ust_fd_plibc_close_range);
176 }
177
178 #if defined(__sun__) || defined(__FreeBSD__)
179 /* Solaris and FreeBSD. */
180 void closefrom(int lowfd)
181 {
182 if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
183 return;
184 }
185
186 (void) lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close);
187 }
188 #elif defined(__NetBSD__) || defined(__OpenBSD__)
189 /* NetBSD and OpenBSD. */
190 int closefrom(int lowfd)
191 {
192 if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
193 errno = ENOSYS;
194 return -1;
195 }
196
197 return lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close);
198 }
199 #else
200 /* As far as we know, this OS does not implement closefrom. */
201 #endif
This page took 0.043733 seconds and 5 git commands to generate.