xref: /illumos-gate/usr/src/lib/libc/port/gen/closefrom.c (revision a87ab1ea)
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 /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*a87ab1eaSBill Sommerfeld  * Copyright 2023 Bill Sommerfeld <sommerfeld@alum.mit.edu>
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287257d1b4Sraf #pragma weak _closefrom = closefrom
297257d1b4Sraf #pragma weak _fdwalk = fdwalk
307c478bd9Sstevel@tonic-gate 
317257d1b4Sraf #include "lint.h"
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <dirent.h>
387c478bd9Sstevel@tonic-gate #include <limits.h>
397c478bd9Sstevel@tonic-gate #include <errno.h>
407c478bd9Sstevel@tonic-gate #include <alloca.h>
417c478bd9Sstevel@tonic-gate #include <sys/resource.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* Initial size of the open file descriptor array */
447c478bd9Sstevel@tonic-gate #define	FDS_SZ	(1024 * sizeof (int))
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Iterate over all open file descriptors, calling 'func' on each one.
487c478bd9Sstevel@tonic-gate  * Terminate the iteration when 'func' returns non-zero or when all
497c478bd9Sstevel@tonic-gate  * open file descriptors have been processed.  Return the value of
507c478bd9Sstevel@tonic-gate  * the last non-zero return from 'func' or zero.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate int
fdwalk(int (* func)(void *,int),void * cd)537c478bd9Sstevel@tonic-gate fdwalk(int (*func)(void *, int), void *cd)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	int err = errno;
567c478bd9Sstevel@tonic-gate 	int rv = 0;
577c478bd9Sstevel@tonic-gate 	int max_fds = INT_MAX;
587c478bd9Sstevel@tonic-gate 	struct rlimit rl;
597c478bd9Sstevel@tonic-gate 	DIR *dirp;
604ca944bdSraf 	struct dirent64 *dp;
617c478bd9Sstevel@tonic-gate 	int *fds;
627c478bd9Sstevel@tonic-gate 	size_t fds_sz;
637c478bd9Sstevel@tonic-gate 	int nfds;
647c478bd9Sstevel@tonic-gate 	int i;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	nfds = 0;
677c478bd9Sstevel@tonic-gate 	fds = alloca(FDS_SZ);
687c478bd9Sstevel@tonic-gate 	fds_sz = FDS_SZ;
697c478bd9Sstevel@tonic-gate 	if ((dirp = opendir("/proc/self/fd")) != NULL) {
707c478bd9Sstevel@tonic-gate 		/*
717c478bd9Sstevel@tonic-gate 		 * Collect all of the open file descriptors and close
727c478bd9Sstevel@tonic-gate 		 * the directory before calling 'func' on any of them.
737c478bd9Sstevel@tonic-gate 		 */
744ca944bdSraf 		while ((dp = readdir64(dirp)) != NULL) {
757c478bd9Sstevel@tonic-gate 			/* skip '.', '..' and the opendir() fd */
767c478bd9Sstevel@tonic-gate 			if (!isdigit(dp->d_name[0]) ||
777c478bd9Sstevel@tonic-gate 			    (i = atoi(dp->d_name)) == dirp->dd_fd)
787c478bd9Sstevel@tonic-gate 				continue;
797c478bd9Sstevel@tonic-gate 			if (fds_sz <= nfds * sizeof (int)) {
807c478bd9Sstevel@tonic-gate 				fds = memcpy(alloca(fds_sz * 2), fds, fds_sz);
817c478bd9Sstevel@tonic-gate 				fds_sz *= 2;
827c478bd9Sstevel@tonic-gate 			}
837c478bd9Sstevel@tonic-gate 			fds[nfds++] = i;
847c478bd9Sstevel@tonic-gate 		}
857c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
867c478bd9Sstevel@tonic-gate 	} else {
877c478bd9Sstevel@tonic-gate 		/*
887c478bd9Sstevel@tonic-gate 		 * We could not open the /proc file descriptor directory.
897c478bd9Sstevel@tonic-gate 		 * We have to do it the hard way.
907c478bd9Sstevel@tonic-gate 		 */
917c478bd9Sstevel@tonic-gate 		if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
927c478bd9Sstevel@tonic-gate 			max_fds = (rl.rlim_max == RLIM_INFINITY)?
937257d1b4Sraf 			    INT_MAX : rl.rlim_max;
947c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_fds; i++) {
957c478bd9Sstevel@tonic-gate 			if (fcntl(i, F_GETFD) < 0)
967c478bd9Sstevel@tonic-gate 				continue;
977c478bd9Sstevel@tonic-gate 			if (fds_sz <= nfds * sizeof (int)) {
987c478bd9Sstevel@tonic-gate 				fds = memcpy(alloca(fds_sz * 2), fds, fds_sz);
997c478bd9Sstevel@tonic-gate 				fds_sz *= 2;
1007c478bd9Sstevel@tonic-gate 			}
1017c478bd9Sstevel@tonic-gate 			fds[nfds++] = i;
1027c478bd9Sstevel@tonic-gate 		}
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * Restore the original value of errno so that
1077c478bd9Sstevel@tonic-gate 	 * the caller sees only the value of errno set
1087c478bd9Sstevel@tonic-gate 	 * by the callback function.
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	errno = err;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * Perform the callbacks on all of the open files.
1147c478bd9Sstevel@tonic-gate 	 */
1157c478bd9Sstevel@tonic-gate 	for (i = 0; i < nfds; i++)
1167c478bd9Sstevel@tonic-gate 		if ((rv = func(cd, fds[i])) != 0)
1177c478bd9Sstevel@tonic-gate 			break;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	return (rv);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Call-back function for closefrom(), below.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate static int
void_close(void * lowp,int fd)1267c478bd9Sstevel@tonic-gate void_close(void *lowp, int fd)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	if (fd >= *(int *)lowp)
1297c478bd9Sstevel@tonic-gate 		(void) close(fd);
1307c478bd9Sstevel@tonic-gate 	return (0);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * Close all open file descriptors greater than or equal to lowfd.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate void
closefrom(int lowfd)1377c478bd9Sstevel@tonic-gate closefrom(int lowfd)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	int low = (lowfd < 0)? 0 : lowfd;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	/*
1427c478bd9Sstevel@tonic-gate 	 * Close lowfd right away as a hedge against failing
1437c478bd9Sstevel@tonic-gate 	 * to open the /proc file descriptor directory due
1447c478bd9Sstevel@tonic-gate 	 * all file descriptors being currently used up.
1457c478bd9Sstevel@tonic-gate 	 */
146*a87ab1eaSBill Sommerfeld 	(void) close(low);
1477c478bd9Sstevel@tonic-gate 	(void) fdwalk(void_close, &low);
1487c478bd9Sstevel@tonic-gate }
149