|
8 | 8 | #ifdef HAVE_SYS_TYPES_H |
9 | 9 | #include <sys/types.h> |
10 | 10 | #endif |
| 11 | +#if defined(HAVE_SYS_STAT_H) && defined(__FreeBSD__) |
| 12 | +#include <sys/stat.h> |
| 13 | +#endif |
11 | 14 | #ifdef HAVE_SYS_SYSCALL_H |
12 | 15 | #include <sys/syscall.h> |
13 | 16 | #endif |
|
26 | 29 | # endif |
27 | 30 | #endif |
28 | 31 |
|
29 | | -#define LINUX_SOLARIS_FD_DIR "/proc/self/fd" |
30 | | -#define BSD_OSX_FD_DIR "/dev/fd" |
| 32 | +#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) |
| 33 | +# define FD_DIR "/dev/fd" |
| 34 | +#else |
| 35 | +# define FD_DIR "/proc/self/fd" |
| 36 | +#endif |
31 | 37 |
|
32 | 38 | #define POSIX_CALL(call) if ((call) == -1) goto error |
33 | 39 |
|
@@ -62,6 +68,28 @@ static int _pos_int_from_ascii(char *name) |
62 | 68 | } |
63 | 69 |
|
64 | 70 |
|
| 71 | +#if defined(__FreeBSD__) |
| 72 | +/* When /dev/fd isn't mounted it is often a static directory populated |
| 73 | + * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD and OpenBSD. |
| 74 | + * NetBSD and OpenBSD have a /proc fs available (though not necessarily |
| 75 | + * mounted) and do not have fdescfs for /dev/fd. MacOS X has a devfs |
| 76 | + * that properly supports /dev/fd. |
| 77 | + */ |
| 78 | +static int _is_fdescfs_mounted_on_dev_fd() |
| 79 | +{ |
| 80 | + struct stat dev_stat; |
| 81 | + struct stat dev_fd_stat; |
| 82 | + if (stat("/dev", &dev_stat) != 0) |
| 83 | + return 0; |
| 84 | + if (stat(FD_DIR, &dev_fd_stat) != 0) |
| 85 | + return 0; |
| 86 | + if (dev_stat.st_dev == dev_fd_stat.st_dev) |
| 87 | + return 0; /* / == /dev == /dev/fd means it is static. #fail */ |
| 88 | + return 1; |
| 89 | +} |
| 90 | +#endif |
| 91 | + |
| 92 | + |
65 | 93 | /* Returns 1 if there is a problem with fd_sequence, 0 otherwise. */ |
66 | 94 | static int _sanity_check_python_fd_sequence(PyObject *fd_sequence) |
67 | 95 | { |
@@ -169,8 +197,7 @@ static void _close_open_fd_range_safe(int start_fd, int end_fd, |
169 | 197 | int fd_dir_fd; |
170 | 198 | if (start_fd >= end_fd) |
171 | 199 | return; |
172 | | - fd_dir_fd = open(LINUX_SOLARIS_FD_DIR, O_RDONLY | O_CLOEXEC, 0); |
173 | | - /* Not trying to open the BSD_OSX path as this is currently Linux only. */ |
| 200 | + fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); |
174 | 201 | if (fd_dir_fd == -1) { |
175 | 202 | /* No way to get a list of open fds. */ |
176 | 203 | _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep); |
@@ -237,9 +264,12 @@ static void _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd, |
237 | 264 | if (start_fd >= end_fd) |
238 | 265 | return; |
239 | 266 |
|
240 | | - proc_fd_dir = opendir(BSD_OSX_FD_DIR); |
241 | | - if (!proc_fd_dir) |
242 | | - proc_fd_dir = opendir(LINUX_SOLARIS_FD_DIR); |
| 267 | +#if defined(__FreeBSD__) |
| 268 | + if (!_is_fdescfs_mounted_on_dev_fd()) |
| 269 | + proc_fd_dir = NULL; |
| 270 | + else |
| 271 | +#endif |
| 272 | + proc_fd_dir = opendir(FD_DIR); |
243 | 273 | if (!proc_fd_dir) { |
244 | 274 | /* No way to get a list of open fds. */ |
245 | 275 | _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep); |
@@ -361,8 +391,16 @@ static void child_exec(char *const exec_array[], |
361 | 391 | POSIX_CALL(close(errwrite)); |
362 | 392 | } |
363 | 393 |
|
364 | | - if (close_fds) |
365 | | - _close_open_fd_range(3, max_fd, py_fds_to_keep); |
| 394 | + if (close_fds) { |
| 395 | + int local_max_fd = max_fd; |
| 396 | +#if defined(__NetBSD__) |
| 397 | + local_max_fd = fcntl(0, F_MAXFD); |
| 398 | + if (local_max_fd < 0) |
| 399 | + local_max_fd = max_fd; |
| 400 | +#endif |
| 401 | + /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */ |
| 402 | + _close_open_fd_range(3, local_max_fd, py_fds_to_keep); |
| 403 | + } |
366 | 404 |
|
367 | 405 | if (cwd) |
368 | 406 | POSIX_CALL(chdir(cwd)); |
|
0 commit comments