17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54ca944bdSraf * Common Development and Distribution License (the "License").
64ca944bdSraf * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
214ca944bdSraf
227c478bd9Sstevel@tonic-gate /*
23*7257d1b4Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
29*7257d1b4Sraf #pragma weak _closefrom = closefrom
30*7257d1b4Sraf #pragma weak _fdwalk = fdwalk
317c478bd9Sstevel@tonic-gate
32*7257d1b4Sraf #include "lint.h"
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <dirent.h>
397c478bd9Sstevel@tonic-gate #include <limits.h>
407c478bd9Sstevel@tonic-gate #include <errno.h>
417c478bd9Sstevel@tonic-gate #include <alloca.h>
427c478bd9Sstevel@tonic-gate #include <sys/resource.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate /* Initial size of the open file descriptor array */
457c478bd9Sstevel@tonic-gate #define FDS_SZ (1024 * sizeof (int))
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate * Iterate over all open file descriptors, calling 'func' on each one.
497c478bd9Sstevel@tonic-gate * Terminate the iteration when 'func' returns non-zero or when all
507c478bd9Sstevel@tonic-gate * open file descriptors have been processed. Return the value of
517c478bd9Sstevel@tonic-gate * the last non-zero return from 'func' or zero.
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate int
fdwalk(int (* func)(void *,int),void * cd)547c478bd9Sstevel@tonic-gate fdwalk(int (*func)(void *, int), void *cd)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate int err = errno;
577c478bd9Sstevel@tonic-gate int rv = 0;
587c478bd9Sstevel@tonic-gate int max_fds = INT_MAX;
597c478bd9Sstevel@tonic-gate struct rlimit rl;
607c478bd9Sstevel@tonic-gate DIR *dirp;
614ca944bdSraf struct dirent64 *dp;
627c478bd9Sstevel@tonic-gate int *fds;
637c478bd9Sstevel@tonic-gate size_t fds_sz;
647c478bd9Sstevel@tonic-gate int nfds;
657c478bd9Sstevel@tonic-gate int i;
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate nfds = 0;
687c478bd9Sstevel@tonic-gate fds = alloca(FDS_SZ);
697c478bd9Sstevel@tonic-gate fds_sz = FDS_SZ;
707c478bd9Sstevel@tonic-gate if ((dirp = opendir("/proc/self/fd")) != NULL) {
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate * Collect all of the open file descriptors and close
737c478bd9Sstevel@tonic-gate * the directory before calling 'func' on any of them.
747c478bd9Sstevel@tonic-gate */
754ca944bdSraf while ((dp = readdir64(dirp)) != NULL) {
767c478bd9Sstevel@tonic-gate /* skip '.', '..' and the opendir() fd */
777c478bd9Sstevel@tonic-gate if (!isdigit(dp->d_name[0]) ||
787c478bd9Sstevel@tonic-gate (i = atoi(dp->d_name)) == dirp->dd_fd)
797c478bd9Sstevel@tonic-gate continue;
807c478bd9Sstevel@tonic-gate if (fds_sz <= nfds * sizeof (int)) {
817c478bd9Sstevel@tonic-gate fds = memcpy(alloca(fds_sz * 2), fds, fds_sz);
827c478bd9Sstevel@tonic-gate fds_sz *= 2;
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate fds[nfds++] = i;
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate (void) closedir(dirp);
877c478bd9Sstevel@tonic-gate } else {
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate * We could not open the /proc file descriptor directory.
907c478bd9Sstevel@tonic-gate * We have to do it the hard way.
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
937c478bd9Sstevel@tonic-gate max_fds = (rl.rlim_max == RLIM_INFINITY)?
947c478bd9Sstevel@tonic-gate INT_MAX : rl.rlim_max;
957c478bd9Sstevel@tonic-gate for (i = 0; i < max_fds; i++) {
967c478bd9Sstevel@tonic-gate if (fcntl(i, F_GETFD) < 0)
977c478bd9Sstevel@tonic-gate continue;
987c478bd9Sstevel@tonic-gate if (fds_sz <= nfds * sizeof (int)) {
997c478bd9Sstevel@tonic-gate fds = memcpy(alloca(fds_sz * 2), fds, fds_sz);
1007c478bd9Sstevel@tonic-gate fds_sz *= 2;
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate fds[nfds++] = i;
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate * Restore the original value of errno so that
1087c478bd9Sstevel@tonic-gate * the caller sees only the value of errno set
1097c478bd9Sstevel@tonic-gate * by the callback function.
1107c478bd9Sstevel@tonic-gate */
1117c478bd9Sstevel@tonic-gate errno = err;
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * Perform the callbacks on all of the open files.
1157c478bd9Sstevel@tonic-gate */
1167c478bd9Sstevel@tonic-gate for (i = 0; i < nfds; i++)
1177c478bd9Sstevel@tonic-gate if ((rv = func(cd, fds[i])) != 0)
1187c478bd9Sstevel@tonic-gate break;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate return (rv);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * Call-back function for closefrom(), below.
1257c478bd9Sstevel@tonic-gate */
1267c478bd9Sstevel@tonic-gate static int
void_close(void * lowp,int fd)1277c478bd9Sstevel@tonic-gate void_close(void *lowp, int fd)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate if (fd >= *(int *)lowp)
1307c478bd9Sstevel@tonic-gate (void) close(fd);
1317c478bd9Sstevel@tonic-gate return (0);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate * Close all open file descriptors greater than or equal to lowfd.
1367c478bd9Sstevel@tonic-gate */
1377c478bd9Sstevel@tonic-gate void
closefrom(int lowfd)1387c478bd9Sstevel@tonic-gate closefrom(int lowfd)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate int low = (lowfd < 0)? 0 : lowfd;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate * Close lowfd right away as a hedge against failing
1447c478bd9Sstevel@tonic-gate * to open the /proc file descriptor directory due
1457c478bd9Sstevel@tonic-gate * all file descriptors being currently used up.
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate (void) close(low++);
1487c478bd9Sstevel@tonic-gate (void) fdwalk(void_close, &low);
1497c478bd9Sstevel@tonic-gate }
150