]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2008-2015 Tobias Brunner | |
3 | * Copyright (C) 2005-2008 Martin Willi | |
4 | * HSR Hochschule fuer Technik Rapperswil | |
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. | |
15 | */ | |
16 | ||
17 | #include "utils.h" | |
18 | ||
19 | #include <sys/types.h> | |
20 | #include <unistd.h> | |
21 | #include <limits.h> | |
22 | #include <ctype.h> | |
23 | #include <errno.h> | |
24 | #ifndef WIN32 | |
25 | # include <signal.h> | |
26 | #endif | |
27 | ||
28 | #ifndef HAVE_CLOSEFROM | |
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 { | |
36 | uint64_t d_ino; | |
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) */ | |
43 | # include <dirent.h> | |
44 | #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ | |
45 | #endif | |
46 | ||
47 | #include <library.h> | |
48 | #include <collections/enumerator.h> | |
49 | ||
50 | #define FD_DIR "/proc/self/fd" | |
51 | ||
52 | #ifdef WIN32 | |
53 | ||
54 | #include <threading/mutex.h> | |
55 | #include <threading/condvar.h> | |
56 | ||
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 | */ | |
75 | static BOOL WINAPI handler(DWORD dwCtrlType) | |
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; | |
121 | ||
122 | sigemptyset(&set); | |
123 | sigaddset(&set, SIGINT); | |
124 | sigaddset(&set, SIGTERM); | |
125 | ||
126 | sigprocmask(SIG_BLOCK, &set, NULL); | |
127 | while (sigwaitinfo(&set, NULL) == -1 && errno == EINTR) | |
128 | { | |
129 | /* wait for signal */ | |
130 | } | |
131 | } | |
132 | ||
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 */ | |
153 | ||
154 | #ifndef HAVE_CLOSEFROM | |
155 | /** | |
156 | * Described in header. | |
157 | */ | |
158 | void closefrom(int low_fd) | |
159 | { | |
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 | { | |
173 | while ((len = syscall(__NR_getdents64, dir_fd, buffer, | |
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. */ | |
197 | DIR *dir; | |
198 | struct dirent *entry; | |
199 | ||
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 | ||
207 | dir = opendir(FD_DIR); | |
208 | if (dir) | |
209 | { | |
210 | #ifdef HAVE_DIRFD | |
211 | dir_fd = dirfd(dir); | |
212 | #endif | |
213 | while ((entry = readdir(dir))) | |
214 | { | |
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) | |
221 | { | |
222 | close(fd); | |
223 | } | |
224 | } | |
225 | closedir(dir); | |
226 | return; | |
227 | } | |
228 | #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ | |
229 | ||
230 | /* ...fall back to closing all fds otherwise */ | |
231 | #ifdef WIN32 | |
232 | max_fd = _getmaxstdio(); | |
233 | #else | |
234 | max_fd = (int)sysconf(_SC_OPEN_MAX); | |
235 | #endif | |
236 | if (max_fd < 0) | |
237 | { | |
238 | max_fd = 256; | |
239 | } | |
240 | for (fd = low_fd; fd < max_fd; fd++) | |
241 | { | |
242 | close(fd); | |
243 | } | |
244 | } | |
245 | #endif /* HAVE_CLOSEFROM */ | |
246 | ||
247 | /** | |
248 | * return null | |
249 | */ | |
250 | void *return_null() | |
251 | { | |
252 | return NULL; | |
253 | } | |
254 | ||
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 | ||
271 | /** | |
272 | * nop operation | |
273 | */ | |
274 | void nop() | |
275 | { | |
276 | } | |
277 | ||
278 | /** | |
279 | * See header | |
280 | */ | |
281 | void utils_init() | |
282 | { | |
283 | #ifdef WIN32 | |
284 | windows_init(); | |
285 | #endif | |
286 | atomics_init(); | |
287 | strerror_init(); | |
288 | } | |
289 | ||
290 | /** | |
291 | * See header | |
292 | */ | |
293 | void utils_deinit() | |
294 | { | |
295 | #ifdef WIN32 | |
296 | windows_deinit(); | |
297 | #endif | |
298 | atomics_deinit(); | |
299 | strerror_deinit(); | |
300 | } |