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 * Copyright 2023 Bill Sommerfeld <sommerfeld@alum.mit.edu> 26 */ 27 28 #pragma weak _closefrom = closefrom 29 #pragma weak _fdwalk = fdwalk 30 31 #include "lint.h" 32 #include <ctype.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <dirent.h> 38 #include <limits.h> 39 #include <errno.h> 40 #include <alloca.h> 41 #include <sys/resource.h> 42 43 /* Initial size of the open file descriptor array */ 44 #define FDS_SZ (1024 * sizeof (int)) 45 46 /* 47 * Iterate over all open file descriptors, calling 'func' on each one. 48 * Terminate the iteration when 'func' returns non-zero or when all 49 * open file descriptors have been processed. Return the value of 50 * the last non-zero return from 'func' or zero. 51 */ 52 int 53 fdwalk(int (*func)(void *, int), void *cd) 54 { 55 int err = errno; 56 int rv = 0; 57 int max_fds = INT_MAX; 58 struct rlimit rl; 59 DIR *dirp; 60 struct dirent64 *dp; 61 int *fds; 62 size_t fds_sz; 63 int nfds; 64 int i; 65 66 nfds = 0; 67 fds = alloca(FDS_SZ); 68 fds_sz = FDS_SZ; 69 if ((dirp = opendir("/proc/self/fd")) != NULL) { 70 /* 71 * Collect all of the open file descriptors and close 72 * the directory before calling 'func' on any of them. 73 */ 74 while ((dp = readdir64(dirp)) != NULL) { 75 /* skip '.', '..' and the opendir() fd */ 76 if (!isdigit(dp->d_name[0]) || 77 (i = atoi(dp->d_name)) == dirp->dd_fd) 78 continue; 79 if (fds_sz <= nfds * sizeof (int)) { 80 fds = memcpy(alloca(fds_sz * 2), fds, fds_sz); 81 fds_sz *= 2; 82 } 83 fds[nfds++] = i; 84 } 85 (void) closedir(dirp); 86 } else { 87 /* 88 * We could not open the /proc file descriptor directory. 89 * We have to do it the hard way. 90 */ 91 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) 92 max_fds = (rl.rlim_max == RLIM_INFINITY)? 93 INT_MAX : rl.rlim_max; 94 for (i = 0; i < max_fds; i++) { 95 if (fcntl(i, F_GETFD) < 0) 96 continue; 97 if (fds_sz <= nfds * sizeof (int)) { 98 fds = memcpy(alloca(fds_sz * 2), fds, fds_sz); 99 fds_sz *= 2; 100 } 101 fds[nfds++] = i; 102 } 103 } 104 105 /* 106 * Restore the original value of errno so that 107 * the caller sees only the value of errno set 108 * by the callback function. 109 */ 110 errno = err; 111 112 /* 113 * Perform the callbacks on all of the open files. 114 */ 115 for (i = 0; i < nfds; i++) 116 if ((rv = func(cd, fds[i])) != 0) 117 break; 118 119 return (rv); 120 } 121 122 /* 123 * Call-back function for closefrom(), below. 124 */ 125 static int 126 void_close(void *lowp, int fd) 127 { 128 if (fd >= *(int *)lowp) 129 (void) close(fd); 130 return (0); 131 } 132 133 /* 134 * Close all open file descriptors greater than or equal to lowfd. 135 */ 136 void 137 closefrom(int lowfd) 138 { 139 int low = (lowfd < 0)? 0 : lowfd; 140 141 /* 142 * Close lowfd right away as a hedge against failing 143 * to open the /proc file descriptor directory due 144 * all file descriptors being currently used up. 145 */ 146 (void) close(low); 147 (void) fdwalk(void_close, &low); 148 } 149