xref: /freebsd/tools/build/cross-build/closefrom.c (revision e25152834cdf3b353892835a4f3b157e066a8ed4)
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