1*7ec1ec4fSAlex Richardson /*
2*7ec1ec4fSAlex Richardson * Copyright (c) 2004-2005, 2007, 2010, 2012-2014
3*7ec1ec4fSAlex Richardson * Todd C. Miller <Todd.Miller@courtesan.com>
4*7ec1ec4fSAlex Richardson *
5*7ec1ec4fSAlex Richardson * Permission to use, copy, modify, and distribute this software for any
6*7ec1ec4fSAlex Richardson * purpose with or without fee is hereby granted, provided that the above
7*7ec1ec4fSAlex Richardson * copyright notice and this permission notice appear in all copies.
8*7ec1ec4fSAlex Richardson *
9*7ec1ec4fSAlex Richardson * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*7ec1ec4fSAlex Richardson * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*7ec1ec4fSAlex Richardson * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*7ec1ec4fSAlex Richardson * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*7ec1ec4fSAlex Richardson * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*7ec1ec4fSAlex Richardson * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*7ec1ec4fSAlex Richardson * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*7ec1ec4fSAlex Richardson */
17*7ec1ec4fSAlex Richardson
18*7ec1ec4fSAlex Richardson // #include <config.h>
19*7ec1ec4fSAlex Richardson
20*7ec1ec4fSAlex Richardson #include <sys/types.h>
21*7ec1ec4fSAlex Richardson #include <unistd.h>
22*7ec1ec4fSAlex Richardson #include <stdio.h>
23*7ec1ec4fSAlex Richardson #ifdef STDC_HEADERS
24*7ec1ec4fSAlex Richardson # include <stdlib.h>
25*7ec1ec4fSAlex Richardson # include <stddef.h>
26*7ec1ec4fSAlex Richardson #else
27*7ec1ec4fSAlex Richardson # ifdef HAVE_STDLIB_H
28*7ec1ec4fSAlex Richardson # include <stdlib.h>
29*7ec1ec4fSAlex Richardson # endif
30*7ec1ec4fSAlex Richardson #endif /* STDC_HEADERS */
31*7ec1ec4fSAlex Richardson #include <fcntl.h>
32*7ec1ec4fSAlex Richardson #include <limits.h>
33*7ec1ec4fSAlex Richardson #ifdef HAVE_PSTAT_GETPROC
34*7ec1ec4fSAlex Richardson # include <sys/param.h>
35*7ec1ec4fSAlex Richardson # include <sys/pstat.h>
36*7ec1ec4fSAlex Richardson #else
37*7ec1ec4fSAlex Richardson # ifdef HAVE_DIRENT_H
38*7ec1ec4fSAlex Richardson # include <dirent.h>
39*7ec1ec4fSAlex Richardson # define NAMLEN(dirent) strlen((dirent)->d_name)
40*7ec1ec4fSAlex Richardson # else
41*7ec1ec4fSAlex Richardson # define dirent direct
42*7ec1ec4fSAlex Richardson # define NAMLEN(dirent) (dirent)->d_namlen
43*7ec1ec4fSAlex Richardson # ifdef HAVE_SYS_NDIR_H
44*7ec1ec4fSAlex Richardson # include <sys/ndir.h>
45*7ec1ec4fSAlex Richardson # endif
46*7ec1ec4fSAlex Richardson # ifdef HAVE_SYS_DIR_H
47*7ec1ec4fSAlex Richardson # include <sys/dir.h>
48*7ec1ec4fSAlex Richardson # endif
49*7ec1ec4fSAlex Richardson # ifdef HAVE_NDIR_H
50*7ec1ec4fSAlex Richardson # include <ndir.h>
51*7ec1ec4fSAlex Richardson # endif
52*7ec1ec4fSAlex Richardson # endif
53*7ec1ec4fSAlex Richardson #endif
54*7ec1ec4fSAlex Richardson
55*7ec1ec4fSAlex Richardson #ifndef OPEN_MAX
56*7ec1ec4fSAlex Richardson # define OPEN_MAX 256
57*7ec1ec4fSAlex Richardson #endif
58*7ec1ec4fSAlex Richardson
59*7ec1ec4fSAlex Richardson #if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD)
60*7ec1ec4fSAlex Richardson # define closefrom closefrom_fallback
61*7ec1ec4fSAlex Richardson #endif
62*7ec1ec4fSAlex Richardson
63*7ec1ec4fSAlex Richardson static inline void
closefrom_close(int fd)64*7ec1ec4fSAlex Richardson closefrom_close(int fd)
65*7ec1ec4fSAlex Richardson {
66*7ec1ec4fSAlex Richardson #ifdef __APPLE__
67*7ec1ec4fSAlex Richardson /* Avoid potential libdispatch crash when we close its fds. */
68*7ec1ec4fSAlex Richardson (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
69*7ec1ec4fSAlex Richardson #else
70*7ec1ec4fSAlex Richardson (void)close(fd);
71*7ec1ec4fSAlex Richardson #endif
72*7ec1ec4fSAlex Richardson }
73*7ec1ec4fSAlex Richardson
74*7ec1ec4fSAlex Richardson /*
75*7ec1ec4fSAlex Richardson * Close all file descriptors greater than or equal to lowfd.
76*7ec1ec4fSAlex Richardson * This is the expensive (fallback) method.
77*7ec1ec4fSAlex Richardson */
78*7ec1ec4fSAlex Richardson void
closefrom_fallback(int lowfd)79*7ec1ec4fSAlex Richardson closefrom_fallback(int lowfd)
80*7ec1ec4fSAlex Richardson {
81*7ec1ec4fSAlex Richardson long fd, maxfd;
82*7ec1ec4fSAlex Richardson
83*7ec1ec4fSAlex Richardson /*
84*7ec1ec4fSAlex Richardson * Fall back on sysconf() or getdtablesize(). We avoid checking
85*7ec1ec4fSAlex Richardson * resource limits since it is possible to open a file descriptor
86*7ec1ec4fSAlex Richardson * and then drop the rlimit such that it is below the open fd.
87*7ec1ec4fSAlex Richardson */
88*7ec1ec4fSAlex Richardson #ifdef HAVE_SYSCONF
89*7ec1ec4fSAlex Richardson maxfd = sysconf(_SC_OPEN_MAX);
90*7ec1ec4fSAlex Richardson #else
91*7ec1ec4fSAlex Richardson maxfd = getdtablesize();
92*7ec1ec4fSAlex Richardson #endif /* HAVE_SYSCONF */
93*7ec1ec4fSAlex Richardson if (maxfd < 0)
94*7ec1ec4fSAlex Richardson maxfd = OPEN_MAX;
95*7ec1ec4fSAlex Richardson
96*7ec1ec4fSAlex Richardson for (fd = lowfd; fd < maxfd; fd++)
97*7ec1ec4fSAlex Richardson closefrom_close(fd);
98*7ec1ec4fSAlex Richardson }
99*7ec1ec4fSAlex Richardson
100*7ec1ec4fSAlex Richardson /*
101*7ec1ec4fSAlex Richardson * Close all file descriptors greater than or equal to lowfd.
102*7ec1ec4fSAlex Richardson * We try the fast way first, falling back on the slow method.
103*7ec1ec4fSAlex Richardson */
104*7ec1ec4fSAlex Richardson #if defined(HAVE_FCNTL_CLOSEM)
105*7ec1ec4fSAlex Richardson void
closefrom(int lowfd)106*7ec1ec4fSAlex Richardson closefrom(int lowfd)
107*7ec1ec4fSAlex Richardson {
108*7ec1ec4fSAlex Richardson if (fcntl(lowfd, F_CLOSEM, 0) == -1)
109*7ec1ec4fSAlex Richardson closefrom_fallback(lowfd);
110*7ec1ec4fSAlex Richardson }
111*7ec1ec4fSAlex Richardson #elif defined(HAVE_PSTAT_GETPROC)
112*7ec1ec4fSAlex Richardson void
closefrom(int lowfd)113*7ec1ec4fSAlex Richardson closefrom(int lowfd)
114*7ec1ec4fSAlex Richardson {
115*7ec1ec4fSAlex Richardson struct pst_status pstat;
116*7ec1ec4fSAlex Richardson int fd;
117*7ec1ec4fSAlex Richardson
118*7ec1ec4fSAlex Richardson if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) {
119*7ec1ec4fSAlex Richardson for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
120*7ec1ec4fSAlex Richardson (void)close(fd);
121*7ec1ec4fSAlex Richardson } else {
122*7ec1ec4fSAlex Richardson closefrom_fallback(lowfd);
123*7ec1ec4fSAlex Richardson }
124*7ec1ec4fSAlex Richardson }
125*7ec1ec4fSAlex Richardson #elif defined(HAVE_DIRFD)
126*7ec1ec4fSAlex Richardson static int
closefrom_procfs(int lowfd)127*7ec1ec4fSAlex Richardson closefrom_procfs(int lowfd)
128*7ec1ec4fSAlex Richardson {
129*7ec1ec4fSAlex Richardson const char *path;
130*7ec1ec4fSAlex Richardson DIR *dirp;
131*7ec1ec4fSAlex Richardson struct dirent *dent;
132*7ec1ec4fSAlex Richardson int *fd_array = NULL;
133*7ec1ec4fSAlex Richardson int fd_array_used = 0;
134*7ec1ec4fSAlex Richardson int fd_array_size = 0;
135*7ec1ec4fSAlex Richardson int ret = 0;
136*7ec1ec4fSAlex Richardson int i;
137*7ec1ec4fSAlex Richardson
138*7ec1ec4fSAlex Richardson /* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
139*7ec1ec4fSAlex Richardson # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
140*7ec1ec4fSAlex Richardson path = "/dev/fd";
141*7ec1ec4fSAlex Richardson # else
142*7ec1ec4fSAlex Richardson path = "/proc/self/fd";
143*7ec1ec4fSAlex Richardson # endif
144*7ec1ec4fSAlex Richardson dirp = opendir(path);
145*7ec1ec4fSAlex Richardson if (dirp == NULL)
146*7ec1ec4fSAlex Richardson return -1;
147*7ec1ec4fSAlex Richardson
148*7ec1ec4fSAlex Richardson while ((dent = readdir(dirp)) != NULL) {
149*7ec1ec4fSAlex Richardson const char *errstr;
150*7ec1ec4fSAlex Richardson int fd;
151*7ec1ec4fSAlex Richardson
152*7ec1ec4fSAlex Richardson fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
153*7ec1ec4fSAlex Richardson if (errstr != NULL || fd == dirfd(dirp))
154*7ec1ec4fSAlex Richardson continue;
155*7ec1ec4fSAlex Richardson
156*7ec1ec4fSAlex Richardson if (fd_array_used >= fd_array_size) {
157*7ec1ec4fSAlex Richardson int *ptr;
158*7ec1ec4fSAlex Richardson
159*7ec1ec4fSAlex Richardson if (fd_array_size > 0)
160*7ec1ec4fSAlex Richardson fd_array_size *= 2;
161*7ec1ec4fSAlex Richardson else
162*7ec1ec4fSAlex Richardson fd_array_size = 32;
163*7ec1ec4fSAlex Richardson
164*7ec1ec4fSAlex Richardson ptr = reallocarray(fd_array, fd_array_size, sizeof(int));
165*7ec1ec4fSAlex Richardson if (ptr == NULL) {
166*7ec1ec4fSAlex Richardson ret = -1;
167*7ec1ec4fSAlex Richardson break;
168*7ec1ec4fSAlex Richardson }
169*7ec1ec4fSAlex Richardson fd_array = ptr;
170*7ec1ec4fSAlex Richardson }
171*7ec1ec4fSAlex Richardson
172*7ec1ec4fSAlex Richardson fd_array[fd_array_used++] = fd;
173*7ec1ec4fSAlex Richardson }
174*7ec1ec4fSAlex Richardson
175*7ec1ec4fSAlex Richardson for (i = 0; i < fd_array_used; i++)
176*7ec1ec4fSAlex Richardson closefrom_close(fd_array[i]);
177*7ec1ec4fSAlex Richardson
178*7ec1ec4fSAlex Richardson free(fd_array);
179*7ec1ec4fSAlex Richardson (void)closedir(dirp);
180*7ec1ec4fSAlex Richardson
181*7ec1ec4fSAlex Richardson return ret;
182*7ec1ec4fSAlex Richardson }
183*7ec1ec4fSAlex Richardson
184*7ec1ec4fSAlex Richardson void
closefrom(int lowfd)185*7ec1ec4fSAlex Richardson closefrom(int lowfd)
186*7ec1ec4fSAlex Richardson {
187*7ec1ec4fSAlex Richardson if (closefrom_procfs(lowfd) == 0)
188*7ec1ec4fSAlex Richardson return;
189*7ec1ec4fSAlex Richardson
190*7ec1ec4fSAlex Richardson closefrom_fallback(lowfd);
191*7ec1ec4fSAlex Richardson }
192*7ec1ec4fSAlex Richardson #endif /* HAVE_FCNTL_CLOSEM */
193