1 : /*
2 : * closefrom.c - closefrom() replacement
3 : * $Id: closefrom.c 1329 2006-05-09 19:29:45Z remi $
4 : */
5 :
6 : /***********************************************************************
7 : * Copyright © 2006 Rémi Denis-Courmont. *
8 : * This program is free software; you can redistribute and/or modify *
9 : * it under the terms of the GNU General Public License as published *
10 : * by the Free Software Foundation; version 2 of the license. *
11 : * *
12 : * This program is distributed in the hope that it will be useful, *
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
15 : * See the GNU General Public License for more details. *
16 : * *
17 : * You should have received a copy of the GNU General Public License *
18 : * along with this program; if not, you can get it from: *
19 : * http://www.gnu.org/copyleft/gpl.html *
20 : ***********************************************************************/
21 :
22 : #ifdef HAVE_CONFIG_H
23 : # include <config.h>
24 : #endif
25 :
26 : #include <sys/types.h>
27 : #include <sys/time.h> /* for <sys/resource.h> */
28 : #include <sys/resource.h> /* getrlimit() */
29 : #include <unistd.h>
30 : #include <errno.h> /* errno */
31 : #include <sys/select.h> /* FD_SETSIZE */
32 :
33 : /**
34 : * BSD closefrom() replacement.
35 : *
36 : * We don't handle EINTR error properly;
37 : * this replacement is obviously not atomic.
38 : */
39 : extern int closefrom (int fd)
40 0 : {
41 : struct rlimit lim;
42 0 : unsigned found = 0;
43 : int saved_errno;
44 :
45 0 : if (getrlimit (RLIMIT_NOFILE, &lim))
46 0 : return -1;
47 :
48 0 : saved_errno = errno;
49 :
50 : /*
51 : * Make sure closefrom() does not take ages if the file number limit
52 : * is very big. closefrom() is not supposed to setrlimit(), but it is
53 : * not standard, neither common (Darwin, Linux don't have it at the
54 : * moment, and IIRC, FreeBSD and NetBSD neither).
55 : *
56 : * Rather than put some completely arbitrary limit, we use FD_SETSIZE.
57 : * As such we can warranty that subsequent FD_SET() won't overflow.
58 : * Miredo has a O(1) open file descriptors number behavior anyway. If
59 : * you want to use this in another project, you should first consider
60 : * using BSD kqueue/Linux epoll or a portable wrapper of these
61 : * scalable I/O polling calls, and *THEN* use a higher limit here
62 : * instead of FD_SETSIZE.
63 : *
64 : * Mac OS X returns (2^31 - 1) as its limit, and closefrom() is way
65 : * too long (and intensive) in this case. Linux usually returns 1024,
66 : * though root can raise the limit to 1048576.
67 : */
68 0 : if (lim.rlim_max > FD_SETSIZE)
69 : {
70 0 : if (lim.rlim_cur > FD_SETSIZE)
71 0 : lim.rlim_cur = FD_SETSIZE;
72 0 : lim.rlim_max = FD_SETSIZE;
73 0 : setrlimit (RLIMIT_NOFILE, &lim);
74 : }
75 :
76 0 : while ((unsigned)fd < lim.rlim_max)
77 0 : if (close (fd++) == 0)
78 0 : found++;
79 :
80 0 : if (found == 0)
81 : {
82 0 : errno = EBADF;
83 0 : return -1;
84 : }
85 0 : errno = saved_errno;
86 0 : return 0;
87 : }
|