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 63 static inline void 64 closefrom_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 */ 78 void 79 closefrom_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) 105 void 106 closefrom(int lowfd) 107 { 108 if (fcntl(lowfd, F_CLOSEM, 0) == -1) 109 closefrom_fallback(lowfd); 110 } 111 #elif defined(HAVE_PSTAT_GETPROC) 112 void 113 closefrom(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) 126 static int 127 closefrom_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 184 void 185 closefrom(int lowfd) 186 { 187 if (closefrom_procfs(lowfd) == 0) 188 return; 189 190 closefrom_fallback(lowfd); 191 } 192 #endif /* HAVE_FCNTL_CLOSEM */ 193