1 | /* |
2 | * Copyright © 2012 Collabora, Ltd. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining |
5 | * a copy of this software and associated documentation files (the |
6 | * "Software"), to deal in the Software without restriction, including |
7 | * without limitation the rights to use, copy, modify, merge, publish, |
8 | * distribute, sublicense, and/or sell copies of the Software, and to |
9 | * permit persons to whom the Software is furnished to do so, subject to |
10 | * the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice (including the |
13 | * next paragraph) shall be included in all copies or substantial |
14 | * portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
20 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
21 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | * SOFTWARE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | |
28 | #include <assert.h> |
29 | #include <errno.h> |
30 | #include <dirent.h> |
31 | #include <stdio.h> |
32 | #include <stdlib.h> |
33 | #include <unistd.h> |
34 | #include <time.h> |
35 | #include <sys/time.h> |
36 | #include <sys/resource.h> |
37 | |
38 | #ifdef HAVE_SYS_PRCTL_H |
39 | #include <sys/prctl.h> |
40 | #endif |
41 | |
42 | #include "test-runner.h" |
43 | |
44 | #if defined(__FreeBSD__) |
45 | #include <sys/sysctl.h> |
46 | |
47 | /* |
48 | * On FreeBSD, get file descriptor information using sysctl() since that does |
49 | * not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2). |
50 | */ |
51 | int |
52 | count_open_fds(void) |
53 | { |
54 | int error; |
55 | int nfds; |
56 | int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 }; |
57 | size_t len; |
58 | |
59 | len = sizeof(nfds); |
60 | error = sysctl(mib, 4, &nfds, &len, NULL, 0); |
61 | assert(error == 0 && "sysctl KERN_PROC_NFDS failed." ); |
62 | return nfds; |
63 | } |
64 | #else |
65 | int |
66 | count_open_fds(void) |
67 | { |
68 | DIR *dir; |
69 | struct dirent *ent; |
70 | int count = 0; |
71 | |
72 | /* |
73 | * Using /dev/fd instead of /proc/self/fd should allow this code to |
74 | * work on non-Linux operating systems. |
75 | */ |
76 | dir = opendir(name: "/dev/fd" ); |
77 | assert(dir && "opening /dev/fd failed." ); |
78 | |
79 | errno = 0; |
80 | while ((ent = readdir(dirp: dir))) { |
81 | const char *s = ent->d_name; |
82 | if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) |
83 | continue; |
84 | count++; |
85 | } |
86 | assert(errno == 0 && "reading /dev/fd failed." ); |
87 | |
88 | closedir(dirp: dir); |
89 | |
90 | return count; |
91 | } |
92 | #endif |
93 | |
94 | void |
95 | exec_fd_leak_check(int nr_expected_fds) |
96 | { |
97 | const char *exe = "exec-fd-leak-checker" ; |
98 | char number[16] = { 0 }; |
99 | const char *test_build_dir = getenv(name: "TEST_BUILD_DIR" ); |
100 | char exe_path[256] = { 0 }; |
101 | |
102 | if (test_build_dir == NULL || test_build_dir[0] == 0) { |
103 | test_build_dir = "." ; |
104 | } |
105 | |
106 | snprintf(s: exe_path, maxlen: sizeof exe_path - 1, format: "%s/%s" , test_build_dir, exe); |
107 | |
108 | snprintf(s: number, maxlen: sizeof number - 1, format: "%d" , nr_expected_fds); |
109 | execl(path: exe_path, arg: exe, number, (char *)NULL); |
110 | assert(0 && "execing fd leak checker failed" ); |
111 | } |
112 | |
113 | #define USEC_TO_NSEC(n) (1000 * (n)) |
114 | |
115 | /* our implementation of usleep and sleep functions that are safe to use with |
116 | * timeouts (timeouts are implemented using alarm(), so it is not safe use |
117 | * usleep and sleep. See man pages of these functions) |
118 | */ |
119 | void |
120 | test_usleep(useconds_t usec) |
121 | { |
122 | struct timespec ts = { |
123 | .tv_sec = 0, |
124 | .tv_nsec = USEC_TO_NSEC(usec) |
125 | }; |
126 | |
127 | assert(nanosleep(&ts, NULL) == 0); |
128 | } |
129 | |
130 | /* we must write the whole function instead of |
131 | * wrapping test_usleep, because useconds_t may not |
132 | * be able to contain such a big number of microseconds */ |
133 | void |
134 | test_sleep(unsigned int sec) |
135 | { |
136 | struct timespec ts = { |
137 | .tv_sec = sec, |
138 | .tv_nsec = 0 |
139 | }; |
140 | |
141 | assert(nanosleep(&ts, NULL) == 0); |
142 | } |
143 | |
144 | /** Try to disable coredumps |
145 | * |
146 | * Useful for tests that crash on purpose, to avoid creating a core file |
147 | * or launching an application crash handler service or cluttering coredumpctl. |
148 | * |
149 | * NOTE: Calling this may make the process undebuggable. |
150 | */ |
151 | void |
152 | test_disable_coredumps(void) |
153 | { |
154 | struct rlimit r; |
155 | |
156 | if (getrlimit(RLIMIT_CORE, rlimits: &r) == 0) { |
157 | r.rlim_cur = 0; |
158 | setrlimit(RLIMIT_CORE, rlimits: &r); |
159 | } |
160 | |
161 | #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) |
162 | prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); |
163 | #endif |
164 | } |
165 | |