1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #pragma weak _closefrom = closefrom 30 #pragma weak _fdwalk = fdwalk 31 32 #include "lint.h" 33 #include <ctype.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <fcntl.h> 38 #include <dirent.h> 39 #include <limits.h> 40 #include <errno.h> 41 #include <alloca.h> 42 #include <sys/resource.h> 43 44 /* Initial size of the open file descriptor array */ 45 #define FDS_SZ (1024 * sizeof (int)) 46 47 /* 48 * Iterate over all open file descriptors, calling 'func' on each one. 49 * Terminate the iteration when 'func' returns non-zero or when all 50 * open file descriptors have been processed. Return the value of 51 * the last non-zero return from 'func' or zero. 52 */ 53 int 54 fdwalk(int (*func)(void *, int), void *cd) 55 { 56 int err = errno; 57 int rv = 0; 58 int max_fds = INT_MAX; 59 struct rlimit rl; 60 DIR *dirp; 61 struct dirent64 *dp; 62 int *fds; 63 size_t fds_sz; 64 int nfds; 65 int i; 66 67 nfds = 0; 68 fds = alloca(FDS_SZ); 69 fds_sz = FDS_SZ; 70 if ((dirp = opendir("/proc/self/fd")) != NULL) { 71 /* 72 * Collect all of the open file descriptors and close 73 * the directory before calling 'func' on any of them. 74 */ 75 while ((dp = readdir64(dirp)) != NULL) { 76 /* skip '.', '..' and the opendir() fd */ 77 if (!isdigit(dp->d_name[0]) || 78 (i = atoi(dp->d_name)) == dirp->dd_fd) 79 continue; 80 if (fds_sz <= nfds * sizeof (int)) { 81 fds = memcpy(alloca(fds_sz * 2), fds, fds_sz); 82 fds_sz *= 2; 83 } 84 fds[nfds++] = i; 85 } 86 (void) closedir(dirp); 87 } else { 88 /* 89 * We could not open the /proc file descriptor directory. 90 * We have to do it the hard way. 91 */ 92 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) 93 max_fds = (rl.rlim_max == RLIM_INFINITY)? 94 INT_MAX : rl.rlim_max; 95 for (i = 0; i < max_fds; i++) { 96 if (fcntl(i, F_GETFD) < 0) 97 continue; 98 if (fds_sz <= nfds * sizeof (int)) { 99 fds = memcpy(alloca(fds_sz * 2), fds, fds_sz); 100 fds_sz *= 2; 101 } 102 fds[nfds++] = i; 103 } 104 } 105 106 /* 107 * Restore the original value of errno so that 108 * the caller sees only the value of errno set 109 * by the callback function. 110 */ 111 errno = err; 112 113 /* 114 * Perform the callbacks on all of the open files. 115 */ 116 for (i = 0; i < nfds; i++) 117 if ((rv = func(cd, fds[i])) != 0) 118 break; 119 120 return (rv); 121 } 122 123 /* 124 * Call-back function for closefrom(), below. 125 */ 126 static int 127 void_close(void *lowp, int fd) 128 { 129 if (fd >= *(int *)lowp) 130 (void) close(fd); 131 return (0); 132 } 133 134 /* 135 * Close all open file descriptors greater than or equal to lowfd. 136 */ 137 void 138 closefrom(int lowfd) 139 { 140 int low = (lowfd < 0)? 0 : lowfd; 141 142 /* 143 * Close lowfd right away as a hedge against failing 144 * to open the /proc file descriptor directory due 145 * all file descriptors being currently used up. 146 */ 147 (void) close(low++); 148 (void) fdwalk(void_close, &low); 149 } 150