]>
Commit | Line | Data |
---|---|---|
552cc11b | 1 | /* |
b410d7f8 | 2 | * Copyright (C) 2008-2015 Tobias Brunner |
552cc11b | 3 | * Copyright (C) 2005-2008 Martin Willi |
1b671669 | 4 | * HSR Hochschule fuer Technik Rapperswil |
552cc11b MW |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
552cc11b MW |
15 | */ |
16 | ||
4de7401a MW |
17 | #include "utils.h" |
18 | ||
b410d7f8 | 19 | #include <sys/types.h> |
6c20579a | 20 | #include <unistd.h> |
80e05dc8 | 21 | #include <limits.h> |
b410d7f8 | 22 | #include <ctype.h> |
ef4279f2 | 23 | #include <errno.h> |
66c0801d MW |
24 | #ifndef WIN32 |
25 | # include <signal.h> | |
26 | #endif | |
552cc11b | 27 | |
b410d7f8 | 28 | #ifndef HAVE_CLOSEFROM |
f25f4192 TB |
29 | #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) |
30 | # include <sys/stat.h> | |
31 | # include <fcntl.h> | |
32 | # include <sys/syscall.h> | |
33 | /* This is from the kernel sources. We limit the length of directory names to | |
34 | * 256 as we only use it to enumerate FDs. */ | |
35 | struct linux_dirent64 { | |
b12c53ce | 36 | uint64_t d_ino; |
f25f4192 TB |
37 | int64_t d_off; |
38 | unsigned short d_reclen; | |
39 | unsigned char d_type; | |
40 | char d_name[256]; | |
41 | }; | |
42 | #else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */ | |
b410d7f8 | 43 | # include <dirent.h> |
f25f4192 | 44 | #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ |
b410d7f8 TB |
45 | #endif |
46 | ||
f1c9653e | 47 | #include <library.h> |
f1c9653e | 48 | #include <collections/enumerator.h> |
552cc11b | 49 | |
b410d7f8 TB |
50 | #define FD_DIR "/proc/self/fd" |
51 | ||
66c0801d MW |
52 | #ifdef WIN32 |
53 | ||
80e05dc8 MW |
54 | #include <threading/mutex.h> |
55 | #include <threading/condvar.h> | |
56 | ||
66c0801d MW |
57 | /** |
58 | * Flag to indicate signaled wait_sigint() | |
59 | */ | |
60 | static bool sigint_signaled = FALSE; | |
61 | ||
62 | /** | |
63 | * Condvar to wait in wait_sigint() | |
64 | */ | |
65 | static condvar_t *sigint_cond; | |
66 | ||
67 | /** | |
68 | * Mutex to check signaling() | |
69 | */ | |
70 | static mutex_t *sigint_mutex; | |
71 | ||
72 | /** | |
73 | * Control handler to catch ^C | |
74 | */ | |
cab59c73 | 75 | static BOOL WINAPI handler(DWORD dwCtrlType) |
66c0801d MW |
76 | { |
77 | switch (dwCtrlType) | |
78 | { | |
79 | case CTRL_C_EVENT: | |
80 | case CTRL_BREAK_EVENT: | |
81 | case CTRL_CLOSE_EVENT: | |
82 | sigint_mutex->lock(sigint_mutex); | |
83 | sigint_signaled = TRUE; | |
84 | sigint_cond->signal(sigint_cond); | |
85 | sigint_mutex->unlock(sigint_mutex); | |
86 | return TRUE; | |
87 | default: | |
88 | return FALSE; | |
89 | } | |
90 | } | |
91 | ||
92 | /** | |
93 | * Windows variant | |
94 | */ | |
95 | void wait_sigint() | |
96 | { | |
97 | SetConsoleCtrlHandler(handler, TRUE); | |
98 | ||
99 | sigint_mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
100 | sigint_cond = condvar_create(CONDVAR_TYPE_DEFAULT); | |
101 | ||
102 | sigint_mutex->lock(sigint_mutex); | |
103 | while (!sigint_signaled) | |
104 | { | |
105 | sigint_cond->wait(sigint_cond, sigint_mutex); | |
106 | } | |
107 | sigint_mutex->unlock(sigint_mutex); | |
108 | ||
109 | sigint_mutex->destroy(sigint_mutex); | |
110 | sigint_cond->destroy(sigint_cond); | |
111 | } | |
112 | ||
113 | #else /* !WIN32 */ | |
114 | ||
115 | /** | |
116 | * Unix variant | |
117 | */ | |
118 | void wait_sigint() | |
119 | { | |
120 | sigset_t set; | |
66c0801d MW |
121 | |
122 | sigemptyset(&set); | |
123 | sigaddset(&set, SIGINT); | |
124 | sigaddset(&set, SIGTERM); | |
125 | ||
126 | sigprocmask(SIG_BLOCK, &set, NULL); | |
88b85e02 TB |
127 | while (sigwaitinfo(&set, NULL) == -1 && errno == EINTR) |
128 | { | |
129 | /* wait for signal */ | |
130 | } | |
66c0801d MW |
131 | } |
132 | ||
ef4279f2 TB |
133 | #ifndef HAVE_SIGWAITINFO |
134 | int sigwaitinfo(const sigset_t *set, void *info) | |
135 | { | |
136 | int sig, err; | |
137 | ||
138 | if (info) | |
139 | { /* we don't replicate siginfo_t, fail if anybody tries to use it */ | |
140 | errno = EINVAL; | |
141 | return -1; | |
142 | } | |
143 | err = sigwait(set, &sig); | |
144 | if (err != 0) | |
145 | { | |
146 | errno = err; | |
147 | sig = -1; | |
148 | } | |
149 | return sig; | |
150 | } | |
151 | #endif /* HAVE_SIGWAITINFO */ | |
152 | #endif /* WIN32 */ | |
66c0801d | 153 | |
9a8fdc15 TB |
154 | #ifndef HAVE_CLOSEFROM |
155 | /** | |
156 | * Described in header. | |
157 | */ | |
b410d7f8 | 158 | void closefrom(int low_fd) |
9a8fdc15 | 159 | { |
f25f4192 TB |
160 | int max_fd, dir_fd, fd; |
161 | ||
162 | /* try to close only open file descriptors on Linux... */ | |
163 | #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) | |
164 | /* By directly using a syscall we avoid any calls that might be unsafe after | |
165 | * fork() (e.g. malloc()). */ | |
166 | char buffer[sizeof(struct linux_dirent64)]; | |
167 | struct linux_dirent64 *entry; | |
168 | int offset, len; | |
169 | ||
170 | dir_fd = open("/proc/self/fd", O_RDONLY); | |
171 | if (dir_fd != -1) | |
172 | { | |
5461efe7 | 173 | while ((len = syscall(__NR_getdents64, dir_fd, buffer, |
f25f4192 TB |
174 | sizeof(buffer))) > 0) |
175 | { | |
176 | for (offset = 0; offset < len; offset += entry->d_reclen) | |
177 | { | |
178 | entry = (struct linux_dirent64*)(buffer + offset); | |
179 | if (!isdigit(entry->d_name[0])) | |
180 | { | |
181 | continue; | |
182 | } | |
183 | fd = atoi(entry->d_name); | |
184 | if (fd != dir_fd && fd >= low_fd) | |
185 | { | |
186 | close(fd); | |
187 | } | |
188 | } | |
189 | } | |
190 | close(dir_fd); | |
191 | return; | |
192 | } | |
193 | #else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */ | |
194 | /* This is potentially unsafe when called after fork() in multi-threaded | |
195 | * applications. In particular opendir() will require an allocation. | |
196 | * Depends on how the malloc() implementation handles such situations. */ | |
b410d7f8 TB |
197 | DIR *dir; |
198 | struct dirent *entry; | |
b410d7f8 | 199 | |
6d9cd1d6 TB |
200 | #ifndef HAVE_DIRFD |
201 | /* if we don't have dirfd() lets close the lowest FD and hope it gets reused | |
202 | * by opendir() */ | |
203 | close(low_fd); | |
204 | dir_fd = low_fd++; | |
205 | #endif | |
206 | ||
b410d7f8 TB |
207 | dir = opendir(FD_DIR); |
208 | if (dir) | |
5051bd23 | 209 | { |
6d9cd1d6 | 210 | #ifdef HAVE_DIRFD |
b410d7f8 | 211 | dir_fd = dirfd(dir); |
6d9cd1d6 | 212 | #endif |
b410d7f8 | 213 | while ((entry = readdir(dir))) |
5051bd23 | 214 | { |
b410d7f8 TB |
215 | if (!isdigit(entry->d_name[0])) |
216 | { | |
217 | continue; | |
218 | } | |
219 | fd = atoi(entry->d_name); | |
220 | if (fd != dir_fd && fd >= low_fd) | |
5051bd23 | 221 | { |
b410d7f8 | 222 | close(fd); |
5051bd23 | 223 | } |
5051bd23 | 224 | } |
b410d7f8 TB |
225 | closedir(dir); |
226 | return; | |
5051bd23 | 227 | } |
f25f4192 | 228 | #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ |
5051bd23 TB |
229 | |
230 | /* ...fall back to closing all fds otherwise */ | |
d3c30b35 | 231 | #ifdef WIN32 |
b410d7f8 | 232 | max_fd = _getmaxstdio(); |
d3c30b35 | 233 | #else |
b410d7f8 | 234 | max_fd = (int)sysconf(_SC_OPEN_MAX); |
d3c30b35 | 235 | #endif |
b410d7f8 | 236 | if (max_fd < 0) |
9a8fdc15 | 237 | { |
b410d7f8 | 238 | max_fd = 256; |
9a8fdc15 | 239 | } |
b410d7f8 | 240 | for (fd = low_fd; fd < max_fd; fd++) |
9a8fdc15 TB |
241 | { |
242 | close(fd); | |
243 | } | |
244 | } | |
245 | #endif /* HAVE_CLOSEFROM */ | |
246 | ||
081ae2eb MW |
247 | /** |
248 | * return null | |
249 | */ | |
250 | void *return_null() | |
251 | { | |
252 | return NULL; | |
253 | } | |
254 | ||
da17b016 MW |
255 | /** |
256 | * returns TRUE | |
257 | */ | |
258 | bool return_true() | |
259 | { | |
260 | return TRUE; | |
261 | } | |
262 | ||
263 | /** | |
264 | * returns FALSE | |
265 | */ | |
266 | bool return_false() | |
267 | { | |
268 | return FALSE; | |
269 | } | |
270 | ||
233b853d MW |
271 | /** |
272 | * nop operation | |
273 | */ | |
274 | void nop() | |
275 | { | |
276 | } | |
277 | ||
f1c9653e MW |
278 | /** |
279 | * See header | |
280 | */ | |
281 | void utils_init() | |
282 | { | |
283 | #ifdef WIN32 | |
284 | windows_init(); | |
285 | #endif | |
717313c5 | 286 | atomics_init(); |
f1c9653e MW |
287 | strerror_init(); |
288 | } | |
289 | ||
290 | /** | |
291 | * See header | |
292 | */ | |
293 | void utils_deinit() | |
294 | { | |
295 | #ifdef WIN32 | |
296 | windows_deinit(); | |
297 | #endif | |
717313c5 | 298 | atomics_deinit(); |
f1c9653e MW |
299 | strerror_deinit(); |
300 | } |