Branch data Line data Source code
1 : : /** @file closefrom.cc
2 : : * @brief Implementation of closefrom() function.
3 : : */
4 : : /* Copyright (C) 2010,2011 Olly Betts
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, write to the Free Software
18 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : : */
20 : :
21 : : #include <config.h>
22 : :
23 : : // We don't currently need closefrom() on __WIN32__.
24 : : #if !defined HAVE_CLOSEFROM && !defined __WIN32__
25 : :
26 : : #include "closefrom.h"
27 : :
28 : : #include "safeerrno.h"
29 : : #include "safefcntl.h"
30 : : #include "safeunistd.h"
31 : :
32 : : #if defined __linux__ || defined __APPLE__
33 : : # include "safedirent.h"
34 : : # include <cstdlib>
35 : :
36 : : using namespace std;
37 : : #endif
38 : :
39 : : void
40 : 0 : Xapian::Internal::closefrom(int fd)
41 : : {
42 : : #ifdef F_CLOSEM
43 : : // Apparently supported by at least NetBSD, AIX, IRIX.
44 : : if (fcntl(fd, F_CLOSEM, 0) >= 0)
45 : : return;
46 : : #elif defined __linux__ || defined __APPLE__
47 : : // The loop might close the fd associated with dir if we don't take
48 : : // special care to avoid that by either skipping this fd in the closing
49 : : // loop (if dirfd() is available) or making sure we have a free fd below
50 : : // the first we close in the loop.
51 : : #if !defined HAVE_DIRFD && !defined dirfd
52 : : // Make sure that the lowest fd we have been asked to close is closed, and
53 : : // then raise this lower bound - this should ensure that opendir() gets
54 : : // an fd below the new lower bound.
55 : : while (close(fd) < 0 && errno == EINTR) { }
56 : : ++fd;
57 : : #endif
58 : : #if 0
59 : : // Some platforms (e.g. AIX) have /proc/<pid>/fd but not /proc/self - if
60 : : // any such platforms don't have either closefrom() or F_CLOSEM then this
61 : : // code can be used.
62 : : string path = "/proc/";
63 : : path += str(getpid());
64 : : path += "/fd";
65 : : DIR * dir = opendir(path.c_str());
66 : : #elif defined __linux__
67 : 0 : DIR * dir = opendir("/proc/self/fd");
68 : : #elif defined __APPLE__ // Mac OS X
69 : : DIR * dir = opendir("/dev/fd");
70 : : #endif
71 [ # # ]: 0 : if (dir) {
72 : 0 : while (true) {
73 : 0 : errno = 0;
74 : 0 : struct dirent *entry = readdir(dir);
75 [ # # ]: 0 : if (entry == NULL) {
76 : 0 : closedir(dir);
77 : : // Fallback if readdir() or closedir() fails.
78 [ # # ]: 0 : if (errno) break;
79 : 0 : return;
80 : : }
81 : : char ch;
82 : 0 : ch = entry->d_name[0];
83 [ # # ][ # # ]: 0 : if (ch < '0' || ch > '9')
84 : 0 : continue;
85 : 0 : int n = atoi(entry->d_name);
86 [ # # ]: 0 : if (n >= fd) {
87 : : #if defined HAVE_DIRFD || defined dirfd
88 [ # # ]: 0 : if (n == dirfd(dir)) continue;
89 : : #endif
90 : : // Retry on EINTR.
91 [ # # ][ # # ]: 0 : while (close(n) < 0 && errno == EINTR) { }
[ # # ]
92 : : }
93 : : }
94 : : }
95 : : #endif
96 : 0 : int maxfd = -1;
97 : : #ifdef F_MAXFD
98 : : maxfd = fcntl(0, F_MAXFD);
99 : : #endif
100 [ # # ]: 0 : if (maxfd < 0)
101 : 0 : maxfd = static_cast<int>(sysconf(_SC_OPEN_MAX));
102 [ # # ]: 0 : while (fd < maxfd) {
103 : : // Retry on EINTR; just ignore other errors (we'll get EBADF if fd
104 : : // isn't open so that's OK).
105 [ # # ][ # # ]: 0 : while (close(fd) < 0 && errno == EINTR) { }
[ # # ]
106 : 0 : ++fd;
107 : : }
108 : : }
109 : :
110 : : #endif
|