Commit | Line | Data |
---|---|---|
614c279d | 1 | /* Low-level file-handling. |
ecd75fc8 | 2 | Copyright (C) 2012-2014 Free Software Foundation, Inc. |
614c279d TT |
3 | |
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #ifdef GDBSERVER | |
20 | #include "server.h" | |
21 | #else | |
22 | #include "defs.h" | |
614c279d TT |
23 | #endif |
24 | #include "filestuff.h" | |
25 | #include "gdb_vecs.h" | |
614c279d TT |
26 | #include <fcntl.h> |
27 | #include <unistd.h> | |
614c279d | 28 | #include <sys/types.h> |
53ce3c39 | 29 | #include <sys/stat.h> |
614c279d | 30 | |
5d71132c TT |
31 | #ifdef USE_WIN32API |
32 | #include <winsock2.h> | |
33 | #include <windows.h> | |
8658d16d PA |
34 | #define HAVE_SOCKETS 1 |
35 | #elif defined HAVE_SYS_SOCKET_H | |
5d71132c TT |
36 | #include <sys/socket.h> |
37 | /* Define HAVE_F_GETFD if we plan to use F_GETFD. */ | |
38 | #define HAVE_F_GETFD F_GETFD | |
8658d16d | 39 | #define HAVE_SOCKETS 1 |
5d71132c TT |
40 | #endif |
41 | ||
614c279d TT |
42 | #ifdef HAVE_SYS_RESOURCE_H |
43 | #include <sys/resource.h> | |
44 | #endif /* HAVE_SYS_RESOURCE_H */ | |
45 | ||
46 | #ifndef O_CLOEXEC | |
47 | #define O_CLOEXEC 0 | |
48 | #endif | |
49 | ||
50 | #ifndef SOCK_CLOEXEC | |
51 | #define SOCK_CLOEXEC 0 | |
52 | #endif | |
53 | ||
54 | \f | |
55 | ||
56 | #ifndef HAVE_FDWALK | |
57 | ||
2978b111 | 58 | #include <dirent.h> |
614c279d TT |
59 | |
60 | /* Replacement for fdwalk, if the system doesn't define it. Walks all | |
61 | open file descriptors (though this implementation may walk closed | |
62 | ones as well, depending on the host platform's capabilities) and | |
63 | call FUNC with ARG. If FUNC returns non-zero, stops immediately | |
64 | and returns the same value. Otherwise, returns zero when | |
65 | finished. */ | |
66 | ||
67 | static int | |
68 | fdwalk (int (*func) (void *, int), void *arg) | |
69 | { | |
70 | /* Checking __linux__ isn't great but it isn't clear what would be | |
71 | better. There doesn't seem to be a good way to check for this in | |
72 | configure. */ | |
73 | #ifdef __linux__ | |
74 | DIR *dir; | |
75 | ||
76 | dir = opendir ("/proc/self/fd"); | |
77 | if (dir != NULL) | |
78 | { | |
79 | struct dirent *entry; | |
80 | int result = 0; | |
81 | ||
82 | for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) | |
83 | { | |
84 | long fd; | |
85 | char *tail; | |
86 | int result; | |
87 | ||
88 | errno = 0; | |
89 | fd = strtol (entry->d_name, &tail, 10); | |
90 | if (*tail != '\0' || errno != 0) | |
91 | continue; | |
92 | if ((int) fd != fd) | |
93 | { | |
94 | /* What can we do here really? */ | |
95 | continue; | |
96 | } | |
97 | ||
98 | if (fd == dirfd (dir)) | |
99 | continue; | |
100 | ||
101 | result = func (arg, fd); | |
102 | if (result != 0) | |
103 | break; | |
104 | } | |
105 | ||
106 | closedir (dir); | |
107 | return result; | |
108 | } | |
109 | /* We may fall through to the next case. */ | |
110 | #endif | |
111 | ||
112 | { | |
113 | int max, fd; | |
114 | ||
f9b0da3d | 115 | #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) |
614c279d TT |
116 | struct rlimit rlim; |
117 | ||
118 | if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) | |
119 | max = rlim.rlim_max; | |
120 | else | |
121 | #endif | |
122 | { | |
123 | #ifdef _SC_OPEN_MAX | |
124 | max = sysconf (_SC_OPEN_MAX); | |
125 | #else | |
126 | /* Whoops. */ | |
127 | return 0; | |
128 | #endif /* _SC_OPEN_MAX */ | |
129 | } | |
130 | ||
131 | for (fd = 0; fd < max; ++fd) | |
132 | { | |
133 | struct stat sb; | |
134 | int result; | |
135 | ||
136 | /* Only call FUNC for open fds. */ | |
137 | if (fstat (fd, &sb) == -1) | |
138 | continue; | |
139 | ||
140 | result = func (arg, fd); | |
141 | if (result != 0) | |
142 | return result; | |
143 | } | |
144 | ||
145 | return 0; | |
146 | } | |
147 | } | |
148 | ||
149 | #endif /* HAVE_FDWALK */ | |
150 | ||
151 | \f | |
152 | ||
153 | /* A VEC holding all the fds open when notice_open_fds was called. We | |
154 | don't use a hashtab because libiberty isn't linked into gdbserver; | |
155 | and anyway we don't expect there to be many open fds. */ | |
156 | ||
614c279d TT |
157 | static VEC (int) *open_fds; |
158 | ||
159 | /* An fdwalk callback function used by notice_open_fds. It puts the | |
160 | given file descriptor into the vec. */ | |
161 | ||
162 | static int | |
163 | do_mark_open_fd (void *ignore, int fd) | |
164 | { | |
165 | VEC_safe_push (int, open_fds, fd); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | /* See filestuff.h. */ | |
170 | ||
171 | void | |
172 | notice_open_fds (void) | |
173 | { | |
174 | fdwalk (do_mark_open_fd, NULL); | |
175 | } | |
176 | ||
21ff4686 TT |
177 | /* See filestuff.h. */ |
178 | ||
179 | void | |
180 | mark_fd_no_cloexec (int fd) | |
181 | { | |
182 | do_mark_open_fd (NULL, fd); | |
183 | } | |
184 | ||
185 | /* See filestuff.h. */ | |
186 | ||
187 | void | |
188 | unmark_fd_no_cloexec (int fd) | |
189 | { | |
190 | int i, val; | |
191 | ||
192 | for (i = 0; VEC_iterate (int, open_fds, i, val); ++i) | |
193 | { | |
194 | if (fd == val) | |
195 | { | |
196 | VEC_unordered_remove (int, open_fds, i); | |
197 | return; | |
198 | } | |
199 | } | |
200 | ||
201 | gdb_assert_not_reached (_("fd not found in open_fds")); | |
202 | } | |
203 | ||
614c279d TT |
204 | /* Helper function for close_most_fds that closes the file descriptor |
205 | if appropriate. */ | |
206 | ||
207 | static int | |
208 | do_close (void *ignore, int fd) | |
209 | { | |
210 | int i, val; | |
211 | ||
212 | for (i = 0; VEC_iterate (int, open_fds, i, val); ++i) | |
213 | { | |
214 | if (fd == val) | |
215 | { | |
216 | /* Keep this one open. */ | |
217 | return 0; | |
218 | } | |
219 | } | |
220 | ||
221 | close (fd); | |
222 | return 0; | |
223 | } | |
224 | ||
225 | /* See filestuff.h. */ | |
226 | ||
227 | void | |
228 | close_most_fds (void) | |
229 | { | |
230 | fdwalk (do_close, NULL); | |
231 | } | |
232 | ||
233 | \f | |
234 | ||
235 | /* This is a tri-state flag. When zero it means we haven't yet tried | |
236 | O_CLOEXEC. When positive it means that O_CLOEXEC works on this | |
237 | host. When negative, it means that O_CLOEXEC doesn't work. We | |
238 | track this state because, while gdb might have been compiled | |
239 | against a libc that supplies O_CLOEXEC, there is no guarantee that | |
240 | the kernel supports it. */ | |
241 | ||
242 | static int trust_o_cloexec; | |
243 | ||
244 | /* Mark FD as close-on-exec, ignoring errors. Update | |
245 | TRUST_O_CLOEXEC. */ | |
246 | ||
247 | static void | |
248 | mark_cloexec (int fd) | |
249 | { | |
5d71132c | 250 | #ifdef HAVE_F_GETFD |
614c279d TT |
251 | int old = fcntl (fd, F_GETFD, 0); |
252 | ||
253 | if (old != -1) | |
254 | { | |
255 | fcntl (fd, F_SETFD, old | FD_CLOEXEC); | |
256 | ||
257 | if (trust_o_cloexec == 0) | |
258 | { | |
259 | if ((old & FD_CLOEXEC) != 0) | |
260 | trust_o_cloexec = 1; | |
261 | else | |
262 | trust_o_cloexec = -1; | |
263 | } | |
264 | } | |
5d71132c | 265 | #endif /* HAVE_F_GETFD */ |
614c279d TT |
266 | } |
267 | ||
268 | /* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ | |
269 | ||
270 | static void | |
271 | maybe_mark_cloexec (int fd) | |
272 | { | |
273 | if (trust_o_cloexec <= 0) | |
274 | mark_cloexec (fd); | |
275 | } | |
276 | ||
8658d16d PA |
277 | #ifdef HAVE_SOCKETS |
278 | ||
614c279d TT |
279 | /* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ |
280 | ||
281 | static void | |
282 | socket_mark_cloexec (int fd) | |
283 | { | |
284 | if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) | |
285 | mark_cloexec (fd); | |
286 | } | |
287 | ||
8658d16d PA |
288 | #endif |
289 | ||
614c279d TT |
290 | \f |
291 | ||
292 | /* See filestuff.h. */ | |
293 | ||
294 | int | |
5d71132c | 295 | gdb_open_cloexec (const char *filename, int flags, unsigned long mode) |
614c279d TT |
296 | { |
297 | int fd = open (filename, flags | O_CLOEXEC, mode); | |
298 | ||
299 | if (fd >= 0) | |
300 | maybe_mark_cloexec (fd); | |
301 | ||
302 | return fd; | |
303 | } | |
304 | ||
305 | /* See filestuff.h. */ | |
306 | ||
307 | FILE * | |
308 | gdb_fopen_cloexec (const char *filename, const char *opentype) | |
309 | { | |
c74e1ccf | 310 | FILE *result; |
88505fac PM |
311 | /* Probe for "e" support once. But, if we can tell the operating |
312 | system doesn't know about close on exec mode "e" without probing, | |
313 | skip it. E.g., the Windows runtime issues an "Invalid parameter | |
314 | passed to C runtime function" OutputDebugString warning for | |
315 | unknown modes. Assume that if O_CLOEXEC is zero, then "e" isn't | |
316 | supported. */ | |
c74e1ccf | 317 | static int fopen_e_ever_failed_einval = O_CLOEXEC == 0; |
614c279d | 318 | |
c74e1ccf | 319 | if (!fopen_e_ever_failed_einval) |
614c279d TT |
320 | { |
321 | char *copy; | |
322 | ||
323 | copy = alloca (strlen (opentype) + 2); | |
324 | strcpy (copy, opentype); | |
325 | /* This is a glibc extension but we try it unconditionally on | |
326 | this path. */ | |
327 | strcat (copy, "e"); | |
328 | result = fopen (filename, copy); | |
614c279d | 329 | |
c74e1ccf JK |
330 | if (result == NULL && errno == EINVAL) |
331 | { | |
332 | result = fopen (filename, opentype); | |
333 | if (result != NULL) | |
334 | fopen_e_ever_failed_einval = 1; | |
335 | } | |
614c279d | 336 | } |
c74e1ccf JK |
337 | else |
338 | result = fopen (filename, opentype); | |
614c279d TT |
339 | |
340 | if (result != NULL) | |
341 | maybe_mark_cloexec (fileno (result)); | |
342 | ||
343 | return result; | |
344 | } | |
345 | ||
8658d16d | 346 | #ifdef HAVE_SOCKETS |
614c279d TT |
347 | /* See filestuff.h. */ |
348 | ||
349 | int | |
350 | gdb_socketpair_cloexec (int namespace, int style, int protocol, int filedes[2]) | |
351 | { | |
5d71132c | 352 | #ifdef HAVE_SOCKETPAIR |
614c279d TT |
353 | int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes); |
354 | ||
355 | if (result != -1) | |
356 | { | |
357 | socket_mark_cloexec (filedes[0]); | |
358 | socket_mark_cloexec (filedes[1]); | |
359 | } | |
360 | ||
361 | return result; | |
5d71132c TT |
362 | #else |
363 | gdb_assert_not_reached (_("socketpair not available on this host")); | |
364 | #endif | |
614c279d TT |
365 | } |
366 | ||
367 | /* See filestuff.h. */ | |
368 | ||
369 | int | |
370 | gdb_socket_cloexec (int namespace, int style, int protocol) | |
371 | { | |
372 | int result = socket (namespace, style | SOCK_CLOEXEC, protocol); | |
373 | ||
374 | if (result != -1) | |
375 | socket_mark_cloexec (result); | |
376 | ||
377 | return result; | |
378 | } | |
8658d16d | 379 | #endif |
614c279d TT |
380 | |
381 | /* See filestuff.h. */ | |
382 | ||
383 | int | |
384 | gdb_pipe_cloexec (int filedes[2]) | |
385 | { | |
386 | int result; | |
387 | ||
388 | #ifdef HAVE_PIPE2 | |
389 | result = pipe2 (filedes, O_CLOEXEC); | |
390 | if (result != -1) | |
391 | { | |
392 | maybe_mark_cloexec (filedes[0]); | |
393 | maybe_mark_cloexec (filedes[1]); | |
394 | } | |
395 | #else | |
5d71132c | 396 | #ifdef HAVE_PIPE |
614c279d TT |
397 | result = pipe (filedes); |
398 | if (result != -1) | |
399 | { | |
400 | mark_cloexec (filedes[0]); | |
401 | mark_cloexec (filedes[1]); | |
402 | } | |
5d71132c TT |
403 | #else /* HAVE_PIPE */ |
404 | gdb_assert_not_reached (_("pipe not available on this host")); | |
405 | #endif /* HAVE_PIPE */ | |
406 | #endif /* HAVE_PIPE2 */ | |
614c279d TT |
407 | |
408 | return result; | |
409 | } |