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