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
fdwalk(int (* func)(void *,int),void * cd)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
void_close(void * lowp,int fd)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
closefrom(int lowfd)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