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