1 /* CC0 license (public domain) - see LICENSE file for details */
2 #include <ccan/closefrom/closefrom.h>
9 #include <sys/resource.h>
10 #include <sys/types.h>
14 * https://stackoverflow.com/a/918469
16 * The implementation below is not exhaustive of all the suggested above.
22 * https://www.ibm.com/docs/en/aix/7.2?topic=f-fcntl-dup-dup2-subroutine
28 void closefrom(int fromfd)
30 (void) fcntl(fromfd, F_CLOSEM, 0);
33 bool closefrom_may_be_slow(void)
38 #else /* !HAVE_F_CLOSEM */
40 #if HAVE_NR_CLOSE_RANGE
41 #include <sys/syscall.h>
44 #define PROC_PID_FD_LEN \
46 + 20 /* 64-bit $PID */ \
51 static bool can_get_maxfd(void)
54 int res = fcntl(0, F_MAXFD);
65 static bool can_close_range(void)
67 #if HAVE_NR_CLOSE_RANGE
68 int res = syscall(__NR_close_range, INT_MAX, INT_MAX, 0);
77 /* On Linux, Solaris, AIX, Cygwin, and NetBSD. */
78 static bool can_open_proc_pid_fd(void)
80 char dnam[PROC_PID_FD_LEN];
83 sprintf(dnam, "/proc/%ld/fd", (long) getpid());
91 /* On FreeBSD and MacOS. */
92 static bool can_open_dev_fd(void)
95 dir = opendir("/dev/fd");
102 bool closefrom_may_be_slow(void)
106 else if (can_close_range())
108 else if (can_open_proc_pid_fd())
110 else if (can_open_dev_fd())
116 /* It is possible that we run out of available file descriptors.
117 * However, if we are going to close anyway, we could just try
118 * closing file descriptors until we reach maxfd.
121 DIR *try_opendir(const char *dnam, int *fromfd, int maxfd)
127 if (!dir && (errno == ENFILE || errno == EMFILE)) {
133 } while (!dir && (errno == ENFILE || errno == EMFILE));
138 void closefrom(int fromfd)
140 int saved_errno = errno;
145 char dnam[PROC_PID_FD_LEN];
147 struct dirent *entry;
154 #if HAVE_NR_CLOSE_RANGE
155 res = syscall(__NR_close_range, fromfd, INT_MAX, 0);
160 maxfd = sysconf(_SC_OPEN_MAX);
162 sprintf(dnam, "/proc/%ld/fd", (long) getpid());
163 dir = try_opendir(dnam, &fromfd, maxfd);
165 dir = try_opendir("/dev/fd", &fromfd, maxfd);
168 while ((entry = readdir(dir))) {
172 fd = strtol(entry->d_name, &endp, 10);
173 if (entry->d_name != endp && *endp == '\0' &&
174 fd >= 0 && fd < INT_MAX && fd >= fromfd &&
183 res = fcntl(0, F_MAXFD);
189 for (; fromfd < maxfd; ++fromfd)
196 #endif /* !HAVE_F_CLOSEM */
198 void closefrom_limit(unsigned int arg_limit)
200 rlim_t limit = (rlim_t) arg_limit;
202 struct rlimit nofile;
204 if (!closefrom_may_be_slow())
210 getrlimit(RLIMIT_NOFILE, &nofile);
212 /* Respect the max limit.
213 * If we are not running as root then we cannot raise
214 * it, but we *can* lower the max limit.
216 if (nofile.rlim_max != RLIM_INFINITY && limit > nofile.rlim_max)
217 limit = nofile.rlim_max;
219 nofile.rlim_cur = limit;
220 nofile.rlim_max = limit;
222 setrlimit(RLIMIT_NOFILE, &nofile);
225 #endif /* !HAVE_CLOSEFROM */