1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "../libnetdata.h"
static int fd_is_valid(int fd) {
errno_clear();
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
int os_get_fd_open_max(void) {
static int fd_open_max = CLOSE_RANGE_FD_MAX;
if(fd_open_max != CLOSE_RANGE_FD_MAX)
return fd_open_max;
if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) {
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
fd_open_max = rl.rlim_max;
}
#ifdef _SC_OPEN_MAX
if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) {
fd_open_max = sysconf(_SC_OPEN_MAX);
}
#endif
if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) {
// Arbitrary default if everything else fails
fd_open_max = 65535;
}
return fd_open_max;
}
void os_close_range(int first, int last) {
#if defined(HAVE_CLOSE_RANGE)
if(close_range(first, last, 0) == 0) return;
#endif
#if defined(OS_LINUX)
DIR *dir = opendir("/proc/self/fd");
if (dir != NULL) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
int fd = str2i(entry->d_name);
if (fd >= first && (last == CLOSE_RANGE_FD_MAX || fd <= last) && fd_is_valid(fd))
(void)close(fd);
}
closedir(dir);
return;
}
#endif
// Fallback to looping through all file descriptors if necessary
if (last == CLOSE_RANGE_FD_MAX)
last = os_get_fd_open_max();
for (int fd = first; fd <= last; fd++) {
if (fd_is_valid(fd)) (void)close(fd);
}
}
static int compare_ints(const void *a, const void *b) {
int int_a = *((int*)a);
int int_b = *((int*)b);
return (int_a > int_b) - (int_a < int_b);
}
void os_close_all_non_std_open_fds_except(const int fds[], size_t fds_num) {
if (fds_num == 0 || fds == NULL) {
os_close_range(STDERR_FILENO + 1, CLOSE_RANGE_FD_MAX);
return;
}
// copy the fds array to ensure we will not alter them
int fds_copy[fds_num];
memcpy(fds_copy, fds, sizeof(fds_copy));
qsort(fds_copy, fds_num, sizeof(int), compare_ints);
int start = STDERR_FILENO + 1;
size_t i = 0;
// filter out all fds with a number smaller than our start
for (; i < fds_num; i++)
if(fds_copy[i] >= start) break;
// call os_close_range() as many times as needed
for (; i < fds_num; i++) {
if (fds_copy[i] > start)
os_close_range(start, fds_copy[i] - 1);
start = fds_copy[i] + 1;
}
os_close_range(start, CLOSE_RANGE_FD_MAX);
}
|