Commit | Line | Data |
---|---|---|
95e6d268 | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
95e6d268 | 3 | * |
c0c0989a | 4 | * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
95e6d268 MD |
5 | */ |
6 | ||
95e6d268 MD |
7 | #define _LGPL_SOURCE |
8 | #include <limits.h> | |
9 | #include <stdio.h> | |
10 | #include <sys/types.h> | |
11 | #include <unistd.h> | |
95e6d268 | 12 | #include <dlfcn.h> |
58048764 | 13 | #include <errno.h> |
95e6d268 | 14 | |
fca97dfd MJ |
15 | #include <lttng/ust-common.h> |
16 | ||
9d315d6d | 17 | #include "common/macros.h" |
fca97dfd | 18 | #include "common/ust-fd.h" |
95e6d268 | 19 | |
58048764 | 20 | #define LTTNG_UST_DLSYM_FAILED_PTR 0x1 |
95e6d268 | 21 | |
58048764 MJ |
22 | static int (*__lttng_ust_fd_plibc_close)(int fd) = NULL; |
23 | static int (*__lttng_ust_fd_plibc_fclose)(FILE *stream) = NULL; | |
fca97dfd | 24 | |
58048764 MJ |
25 | /* |
26 | * Use dlsym to find the original libc close() symbol and store it in | |
27 | * __lttng_ust_fd_plibc_close. | |
28 | */ | |
95e6d268 | 29 | static |
58048764 | 30 | void *_lttng_ust_fd_init_plibc_close(void) |
95e6d268 | 31 | { |
58048764 | 32 | if (__lttng_ust_fd_plibc_close == NULL) { |
95e6d268 | 33 | __lttng_ust_fd_plibc_close = dlsym(RTLD_NEXT, "close"); |
58048764 MJ |
34 | |
35 | if (__lttng_ust_fd_plibc_close == NULL) { | |
36 | __lttng_ust_fd_plibc_close = (void *) LTTNG_UST_DLSYM_FAILED_PTR; | |
95e6d268 | 37 | fprintf(stderr, "%s\n", dlerror()); |
95e6d268 MD |
38 | } |
39 | } | |
58048764 MJ |
40 | |
41 | return __lttng_ust_fd_plibc_close; | |
95e6d268 MD |
42 | } |
43 | ||
58048764 MJ |
44 | /* |
45 | * Use dlsym to find the original libc fclose() symbol and store it in | |
46 | * __lttng_ust_fd_plibc_fclose. | |
47 | */ | |
52a20dc7 | 48 | static |
58048764 | 49 | void *_lttng_ust_fd_init_plibc_fclose(void) |
52a20dc7 | 50 | { |
58048764 | 51 | if (__lttng_ust_fd_plibc_fclose == NULL) { |
52a20dc7 | 52 | __lttng_ust_fd_plibc_fclose = dlsym(RTLD_NEXT, "fclose"); |
58048764 MJ |
53 | |
54 | if (__lttng_ust_fd_plibc_fclose == NULL) { | |
55 | __lttng_ust_fd_plibc_fclose = (void *) LTTNG_UST_DLSYM_FAILED_PTR; | |
52a20dc7 | 56 | fprintf(stderr, "%s\n", dlerror()); |
52a20dc7 MD |
57 | } |
58 | } | |
58048764 MJ |
59 | |
60 | return __lttng_ust_fd_plibc_fclose; | |
52a20dc7 MD |
61 | } |
62 | ||
58048764 MJ |
63 | static |
64 | void _lttng_ust_fd_ctor(void) | |
65 | __attribute__((constructor)); | |
66 | static | |
67 | void _lttng_ust_fd_ctor(void) | |
68 | { | |
69 | lttng_ust_common_ctor(); | |
70 | ||
71 | /* | |
72 | * Initialize the function pointers to the original libc symbols in the | |
73 | * constructor since close() has to stay async-signal-safe and as such, | |
74 | * we can't call dlsym() in the override functions. | |
75 | */ | |
76 | (void) _lttng_ust_fd_init_plibc_close(); | |
77 | (void) _lttng_ust_fd_init_plibc_fclose(); | |
78 | } | |
79 | ||
80 | /* | |
81 | * Override the libc close() symbol with our own, allowing applications to | |
82 | * close arbitrary file descriptors. If the fd is owned by lttng-ust, return | |
83 | * -1, errno=EBADF instead of closing it. | |
84 | * | |
85 | * If dlsym failed to find the original libc close() symbol, return -1, | |
86 | * errno=ENOSYS. | |
87 | * | |
88 | * There is a short window before the library constructor has executed where | |
89 | * this wrapper could call dlsym() and thus not be async-signal-safe. | |
90 | */ | |
95e6d268 MD |
91 | int close(int fd) |
92 | { | |
58048764 MJ |
93 | /* |
94 | * We can't retry dlsym here since close is async-signal-safe. | |
95 | */ | |
96 | if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) { | |
97 | errno = ENOSYS; | |
98 | return -1; | |
99 | } | |
100 | ||
101 | return lttng_ust_safe_close_fd(fd, __lttng_ust_fd_plibc_close); | |
95e6d268 MD |
102 | } |
103 | ||
52a20dc7 | 104 | /* |
58048764 MJ |
105 | * Override the libc fclose() symbol with our own, allowing applications to |
106 | * close arbitrary streams. If the fd is owned by lttng-ust, return -1, | |
107 | * errno=EBADF instead of closing it. | |
108 | * | |
109 | * If dlsym failed to find the original libc close() symbol, return -1, | |
110 | * errno=ENOSYS. | |
111 | * | |
112 | * There is a short window before the library constructor has executed where | |
113 | * this wrapper could call dlsym() and thus not be async-signal-safe. | |
114 | * | |
115 | * Note: fcloseall() is not an issue because it closes only the streams it | |
116 | * knows about, which differs from the problems caused by gnulib | |
117 | * close_stdout(), which does an explicit fclose(stdout). | |
52a20dc7 MD |
118 | */ |
119 | int fclose(FILE *stream) | |
120 | { | |
58048764 MJ |
121 | if (_lttng_ust_fd_init_plibc_fclose() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) { |
122 | errno = ENOSYS; | |
123 | return -1; | |
124 | } | |
125 | ||
126 | return lttng_ust_safe_fclose_stream(stream, | |
127 | __lttng_ust_fd_plibc_fclose); | |
52a20dc7 MD |
128 | } |
129 | ||
95e6d268 MD |
130 | #if defined(__sun__) || defined(__FreeBSD__) |
131 | /* Solaris and FreeBSD. */ | |
132 | void closefrom(int lowfd) | |
133 | { | |
58048764 MJ |
134 | if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) { |
135 | return; | |
136 | } | |
137 | ||
23366626 | 138 | (void) lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close); |
95e6d268 MD |
139 | } |
140 | #elif defined(__NetBSD__) || defined(__OpenBSD__) | |
141 | /* NetBSD and OpenBSD. */ | |
142 | int closefrom(int lowfd) | |
143 | { | |
58048764 MJ |
144 | if (_lttng_ust_fd_init_plibc_close() == (void *) LTTNG_UST_DLSYM_FAILED_PTR) { |
145 | errno = ENOSYS; | |
146 | return -1; | |
147 | } | |
148 | ||
23366626 | 149 | return lttng_ust_safe_closefrom_fd(lowfd, __lttng_ust_fd_plibc_close); |
95e6d268 MD |
150 | } |
151 | #else | |
152 | /* As far as we know, this OS does not implement closefrom. */ | |
153 | #endif |