Branch data Line data Source code
1 : : /** @file fdtracker.cc
2 : : * @brief Track leaked file descriptors.
3 : : */
4 : : /* Copyright (C) 2010 Olly Betts
5 : : *
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.
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 : : #include "fdtracker.h"
24 : :
25 : : #include "safeunistd.h"
26 : : #include "safedirent.h"
27 : : #include "safeerrno.h"
28 : :
29 : : #include <iostream>
30 : : #include <cstdlib>
31 : : #include <cstring> // For strerror().
32 : : #include <set>
33 : :
34 : : #include "str.h"
35 : :
36 : : using namespace std;
37 : :
38 : 2969 : FDTracker::~FDTracker()
39 : : {
40 : : #ifndef __WIN32__
41 [ + - ][ # # ]: 2969 : if (dir_void) {
42 : 2969 : DIR * dir = static_cast<DIR*>(dir_void);
43 : 2969 : closedir(dir);
44 : : }
45 : : #endif
46 : 2969 : }
47 : :
48 : : void
49 : 2969 : FDTracker::init()
50 : : {
51 : : #ifndef __WIN32__
52 : 2969 : DIR * dir = opendir("/proc/self/fd");
53 : : // Not all platforms have /proc/self/fd.
54 [ - + ]: 2969 : if (!dir) return;
55 : 2969 : dir_void = static_cast<void*>(dir);
56 : :
57 : 23581 : while (true) {
58 : 23581 : errno = 0;
59 : 23581 : struct dirent * entry = readdir(dir);
60 [ + + ]: 23581 : if (!entry) {
61 [ + - ]: 2969 : if (errno == 0)
62 : 2969 : break;
63 : 0 : cout << "readdir failed: " << strerror(errno) << endl;
64 : 0 : exit(1);
65 : : }
66 : :
67 : 20612 : const char * name = entry->d_name;
68 [ + + ][ - + ]: 20612 : if (name[0] < '0' || name[0] > '9')
69 : 5938 : continue;
70 : :
71 : 14674 : int fd = atoi(name);
72 : 14674 : fds.insert(fd);
73 : : }
74 : : #endif
75 : : }
76 : :
77 : : bool
78 : 2927 : FDTracker::check()
79 : : {
80 : 2927 : bool ok = true;
81 : : #ifndef __WIN32__
82 : 2927 : DIR * dir = static_cast<DIR*>(dir_void);
83 [ - + ]: 2927 : if (!dir) return true;
84 : 2927 : rewinddir(dir);
85 : :
86 : 2927 : message.resize(0);
87 : :
88 : 23248 : while (true) {
89 : 23248 : errno = 0;
90 : 23248 : struct dirent * entry = readdir(dir);
91 [ + + ]: 23248 : if (!entry) {
92 [ + - ]: 2927 : if (errno == 0)
93 : : break;
94 : 0 : cout << "readdir failed: " << strerror(errno) << endl;
95 : 0 : exit(1);
96 : : }
97 : :
98 : 20321 : const char * name = entry->d_name;
99 : :
100 : : // Ignore at least '.' and '..'.
101 [ + + ][ - + ]: 20321 : if (name[0] < '0' || name[0] > '9')
102 : 5854 : continue;
103 : :
104 : 14467 : int fd = atoi(name);
105 [ + + ]: 14467 : if (fds.find(fd) != fds.end()) continue;
106 : :
107 : 3 : message += ' ';
108 : 3 : message += str(fd);
109 : :
110 : 3 : string filename = "/proc/self/fd/";
111 : 3 : filename += name;
112 : :
113 : : char buf[1024];
114 : 3 : int res = readlink(filename.c_str(), buf, sizeof(buf));
115 [ + - ]: 3 : if (res > 0) {
116 : 3 : message += " -> ";
117 : 3 : message.append(buf, res);
118 : : }
119 : :
120 : : // Insert the leaked fd so we don't report it for future tests.
121 : 3 : fds.insert(fd);
122 : 3 : ok = false;
123 : : }
124 : : #endif
125 : 2927 : return ok;
126 [ + - ][ + - ]: 15 : }
|