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 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 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 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 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 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 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