Add close_range wrapper to liblttng-ust-fd.so
[lttng-ust.git] / src / lib / lttng-ust-fd / lttng-ust-fd.c
... / ...
CommitLineData
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
22static int (*__lttng_ust_fd_plibc_close)(int fd) = NULL;
23static int (*__lttng_ust_fd_plibc_fclose)(FILE *stream) = NULL;
24static 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 */
31static
32void *_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 */
50static
51void *_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 */
70static
71void *_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
83static
84void _lttng_ust_fd_ctor(void)
85 __attribute__((constructor));
86static
87void _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 */
112int 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 */
140int 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/*
152 * Override the libc close_range() symbol with our own, allowing
153 * applications to close arbitrary file descriptors. If the fd is owned
154 * by lttng-ust, return -1, errno=EBADF instead of closing it.
155 *
156 * If dlsym failed to find the original libc close_range() symbol,
157 * return -1, errno=ENOSYS.
158 *
159 * There is a short window before the library constructor has executed where
160 * this wrapper could call dlsym() and thus not be async-signal-safe.
161 */
162int close_range(unsigned int first, unsigned int last, int flags)
163{
164 /*
165 * We can't retry dlsym here since close is async-signal-safe.
166 */
167 if (_lttng_ust_fd_init_plibc_close_range() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
168 errno = ENOSYS;
169 return -1;
170 }
171
172 return lttng_ust_safe_close_range_fd(first, last, flags, __lttng_ust_fd_plibc_close_range);
173}
174
175#if defined(__sun__) || defined(__FreeBSD__)
176/* Solaris and FreeBSD. */
177void closefrom(int lowfd)
178{
179 if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
180 return;
181 }
182
183 (void) lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close);
184}
185#elif defined(__NetBSD__) || defined(__OpenBSD__)
186/* NetBSD and OpenBSD. */
187int closefrom(int lowfd)
188{
189 if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) {
190 errno = ENOSYS;
191 return -1;
192 }
193
194 return lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close);
195}
196#else
197/* As far as we know, this OS does not implement closefrom. */
198#endif
This page took 0.022763 seconds and 4 git commands to generate.