mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-28 23:34:53 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			105 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Close a range of file descriptors.  Linux version.
 | |
|    Copyright (C) 2021-2025 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <https://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <arch-fd_to_filename.h>
 | |
| #include <dirent.h>
 | |
| #include <not-cancel.h>
 | |
| #include <stdbool.h>
 | |
| 
 | |
| #if !__ASSUME_CLOSE_RANGE
 | |
| 
 | |
| /* Fallback code: iterates over /proc/self/fd, closing each file descriptor
 | |
|    that fall on the criteria.  If DIRFD_FALLBACK is set, a failure on
 | |
|    /proc/self/fd open will trigger a fallback that tries to close a file
 | |
|    descriptor before proceed.  */
 | |
| _Bool
 | |
| __closefrom_fallback (int from, _Bool dirfd_fallback)
 | |
| {
 | |
|   int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
 | |
|                                0);
 | |
|   if (dirfd == -1)
 | |
|     {
 | |
|       /* Return if procfs can not be opened for some reason.  */
 | |
|       if ((errno != EMFILE && errno != ENFILE && errno != ENOMEM)
 | |
| 	  || !dirfd_fallback)
 | |
| 	return false;
 | |
| 
 | |
|       /* The closefrom should work even when process can't open new files.  */
 | |
|       for (int i = from; i < INT_MAX; i++)
 | |
|         {
 | |
|           int r = __close_nocancel (i);
 | |
|           if (r == 0 || (r == -1 && errno != EBADF))
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|       dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
 | |
|                                0);
 | |
|       if (dirfd == -1)
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|   char buffer[1024];
 | |
|   bool ret = false;
 | |
|   while (true)
 | |
|     {
 | |
|       ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
 | |
|       if (ret == -1)
 | |
|         goto err;
 | |
|       else if (ret == 0)
 | |
|         break;
 | |
| 
 | |
|       /* If any file descriptor is closed it resets the /proc/self position
 | |
|          read again from the start (to obtain any possible kernel update).  */
 | |
|       bool closed = false;
 | |
|       char *begin = buffer, *end = buffer + ret;
 | |
|       while (begin != end)
 | |
|         {
 | |
|           unsigned short int d_reclen;
 | |
|           memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
 | |
|                   sizeof (d_reclen));
 | |
|           const char *dname = begin + offsetof (struct dirent64, d_name);
 | |
|           begin += d_reclen;
 | |
| 
 | |
|           if (dname[0] == '.')
 | |
|             continue;
 | |
| 
 | |
|           int fd = 0;
 | |
|           for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
 | |
|             fd = 10 * fd + (*s - '0');
 | |
| 
 | |
|           if (fd == dirfd || fd < from)
 | |
|             continue;
 | |
| 
 | |
|           /* We ignore close errors because EBADF, EINTR, and EIO means the
 | |
|              descriptor has been released.  */
 | |
|           __close_nocancel (fd);
 | |
|           closed = true;
 | |
|         }
 | |
| 
 | |
|       if (closed && __lseek (dirfd, 0, SEEK_SET) < 0)
 | |
|         goto err;
 | |
|     }
 | |
| 
 | |
|   ret = true;
 | |
| err:
 | |
|   __close_nocancel (dirfd);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| #endif
 |