2 * @brief Track leaked file descriptors.
4 /* Copyright (C) 2010,2014,2015,2018 Olly Betts
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
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.
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
23 #include "fdtracker.h"
25 #ifdef XAPIAN_TESTSUITE_TRACK_FDS
27 #include "safeunistd.h"
28 #include "safedirent.h"
29 #include "safeerrno.h"
33 #include <cstring> // For strerror().
37 #include "stringutils.h"
41 // Directory to try to read open fds from. If this directory doesn't exist
42 // then fd tracking will just be disabled. It seems "/dev/fd" is the more
43 // common name for this. On Linux and Cygwin, "/dev/fd" is usually a symlink
44 // to "/proc/self/fd", but that symlink can sometimes be missing so prefer
45 // the latter on these platforms.
46 #if defined __linux__ || defined __CYGWIN__
47 # define FD_DIRECTORY "/proc/self/fd"
49 # define FD_DIRECTORY "/dev/fd"
52 FDTracker::~FDTracker()
55 DIR * dir
= static_cast<DIR*>(dir_void
);
63 DIR * dir
= opendir(FD_DIRECTORY
);
64 // Not all platforms have such a directory.
66 dir_void
= static_cast<void*>(dir
);
70 struct dirent
* entry
= readdir(dir
);
74 cout
<< "readdir failed: " << strerror(errno
) << endl
;
78 const char * name
= entry
->d_name
;
80 // Ignore at least '.' and '..'.
81 if (name
[0] < '0' || name
[0] > '9')
93 DIR * dir
= static_cast<DIR*>(dir_void
);
94 if (!dir
) return true;
101 struct dirent
* entry
= readdir(dir
);
105 cout
<< "readdir failed: " << strerror(errno
) << endl
;
109 const char * name
= entry
->d_name
;
111 // Ignore at least '.' and '..'.
112 if (name
[0] < '0' || name
[0] > '9')
116 if (fds
.find(fd
) != fds
.end()) continue;
118 string proc_symlink
= FD_DIRECTORY
"/";
119 proc_symlink
+= name
;
122 // On some systems (Solaris, AIX) the entries aren't symlinks, so
123 // don't complain if readlink() fails.
124 int res
= readlink(proc_symlink
.c_str(), buf
, sizeof(buf
));
125 if (res
== CONST_STRLEN("/dev/urandom") &&
126 memcmp(buf
, "/dev/urandom", CONST_STRLEN("/dev/urandom")) == 0) {
127 // /dev/urandom isn't a real leak - something in the C library
128 // opens it lazily (at least on Linux).
137 message
.append(buf
, res
);
140 // Insert the leaked fd so we don't report it for future tests.
147 #endif // XAPIAN_TESTSUITE_TRACK_FDS