]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/fd-util.c
util-lib: introduce dirent-util.[ch] for directory entry calls
[thirdparty/systemd.git] / src / basic / fd-util.c
CommitLineData
3ffd4af2
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "fd-util.h"
6bedfcbb 23#include "parse-util.h"
3ffd4af2 24#include "util.h"
a0956174 25#include "dirent-util.h"
3ffd4af2
LP
26
27int close_nointr(int fd) {
28 assert(fd >= 0);
29
30 if (close(fd) >= 0)
31 return 0;
32
33 /*
34 * Just ignore EINTR; a retry loop is the wrong thing to do on
35 * Linux.
36 *
37 * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
38 * https://bugzilla.gnome.org/show_bug.cgi?id=682819
39 * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
40 * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
41 */
42 if (errno == EINTR)
43 return 0;
44
45 return -errno;
46}
47
48int safe_close(int fd) {
49
50 /*
51 * Like close_nointr() but cannot fail. Guarantees errno is
52 * unchanged. Is a NOP with negative fds passed, and returns
53 * -1, so that it can be used in this syntax:
54 *
55 * fd = safe_close(fd);
56 */
57
58 if (fd >= 0) {
59 PROTECT_ERRNO;
60
61 /* The kernel might return pretty much any error code
62 * via close(), but the fd will be closed anyway. The
63 * only condition we want to check for here is whether
64 * the fd was invalid at all... */
65
66 assert_se(close_nointr(fd) != -EBADF);
67 }
68
69 return -1;
70}
71
72void safe_close_pair(int p[]) {
73 assert(p);
74
75 if (p[0] == p[1]) {
76 /* Special case pairs which use the same fd in both
77 * directions... */
78 p[0] = p[1] = safe_close(p[0]);
79 return;
80 }
81
82 p[0] = safe_close(p[0]);
83 p[1] = safe_close(p[1]);
84}
85
86void close_many(const int fds[], unsigned n_fd) {
87 unsigned i;
88
89 assert(fds || n_fd <= 0);
90
91 for (i = 0; i < n_fd; i++)
92 safe_close(fds[i]);
93}
94
95int fclose_nointr(FILE *f) {
96 assert(f);
97
98 /* Same as close_nointr(), but for fclose() */
99
100 if (fclose(f) == 0)
101 return 0;
102
103 if (errno == EINTR)
104 return 0;
105
106 return -errno;
107}
108
109FILE* safe_fclose(FILE *f) {
110
111 /* Same as safe_close(), but for fclose() */
112
113 if (f) {
114 PROTECT_ERRNO;
115
116 assert_se(fclose_nointr(f) != EBADF);
117 }
118
119 return NULL;
120}
121
122DIR* safe_closedir(DIR *d) {
123
124 if (d) {
125 PROTECT_ERRNO;
126
127 assert_se(closedir(d) >= 0 || errno != EBADF);
128 }
129
130 return NULL;
131}
132
133int fd_nonblock(int fd, bool nonblock) {
134 int flags, nflags;
135
136 assert(fd >= 0);
137
138 flags = fcntl(fd, F_GETFL, 0);
139 if (flags < 0)
140 return -errno;
141
142 if (nonblock)
143 nflags = flags | O_NONBLOCK;
144 else
145 nflags = flags & ~O_NONBLOCK;
146
147 if (nflags == flags)
148 return 0;
149
150 if (fcntl(fd, F_SETFL, nflags) < 0)
151 return -errno;
152
153 return 0;
154}
155
156int fd_cloexec(int fd, bool cloexec) {
157 int flags, nflags;
158
159 assert(fd >= 0);
160
161 flags = fcntl(fd, F_GETFD, 0);
162 if (flags < 0)
163 return -errno;
164
165 if (cloexec)
166 nflags = flags | FD_CLOEXEC;
167 else
168 nflags = flags & ~FD_CLOEXEC;
169
170 if (nflags == flags)
171 return 0;
172
173 if (fcntl(fd, F_SETFD, nflags) < 0)
174 return -errno;
175
176 return 0;
177}
178
179_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
180 unsigned i;
181
182 assert(n_fdset == 0 || fdset);
183
184 for (i = 0; i < n_fdset; i++)
185 if (fdset[i] == fd)
186 return true;
187
188 return false;
189}
190
191int close_all_fds(const int except[], unsigned n_except) {
192 _cleanup_closedir_ DIR *d = NULL;
193 struct dirent *de;
194 int r = 0;
195
196 assert(n_except == 0 || except);
197
198 d = opendir("/proc/self/fd");
199 if (!d) {
200 int fd;
201 struct rlimit rl;
202
203 /* When /proc isn't available (for example in chroots)
204 * the fallback is brute forcing through the fd
205 * table */
206
207 assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
208 for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
209
210 if (fd_in_set(fd, except, n_except))
211 continue;
212
213 if (close_nointr(fd) < 0)
214 if (errno != EBADF && r == 0)
215 r = -errno;
216 }
217
218 return r;
219 }
220
221 while ((de = readdir(d))) {
222 int fd = -1;
223
224 if (hidden_file(de->d_name))
225 continue;
226
227 if (safe_atoi(de->d_name, &fd) < 0)
228 /* Let's better ignore this, just in case */
229 continue;
230
231 if (fd < 3)
232 continue;
233
234 if (fd == dirfd(d))
235 continue;
236
237 if (fd_in_set(fd, except, n_except))
238 continue;
239
240 if (close_nointr(fd) < 0) {
241 /* Valgrind has its own FD and doesn't want to have it closed */
242 if (errno != EBADF && r == 0)
243 r = -errno;
244 }
245 }
246
247 return r;
248}
249
250int same_fd(int a, int b) {
251 struct stat sta, stb;
252 pid_t pid;
253 int r, fa, fb;
254
255 assert(a >= 0);
256 assert(b >= 0);
257
258 /* Compares two file descriptors. Note that semantics are
259 * quite different depending on whether we have kcmp() or we
260 * don't. If we have kcmp() this will only return true for
261 * dup()ed file descriptors, but not otherwise. If we don't
262 * have kcmp() this will also return true for two fds of the same
263 * file, created by separate open() calls. Since we use this
264 * call mostly for filtering out duplicates in the fd store
265 * this difference hopefully doesn't matter too much. */
266
267 if (a == b)
268 return true;
269
270 /* Try to use kcmp() if we have it. */
271 pid = getpid();
272 r = kcmp(pid, pid, KCMP_FILE, a, b);
273 if (r == 0)
274 return true;
275 if (r > 0)
276 return false;
277 if (errno != ENOSYS)
278 return -errno;
279
280 /* We don't have kcmp(), use fstat() instead. */
281 if (fstat(a, &sta) < 0)
282 return -errno;
283
284 if (fstat(b, &stb) < 0)
285 return -errno;
286
287 if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
288 return false;
289
290 /* We consider all device fds different, since two device fds
291 * might refer to quite different device contexts even though
292 * they share the same inode and backing dev_t. */
293
294 if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
295 return false;
296
297 if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
298 return false;
299
300 /* The fds refer to the same inode on disk, let's also check
301 * if they have the same fd flags. This is useful to
302 * distinguish the read and write side of a pipe created with
303 * pipe(). */
304 fa = fcntl(a, F_GETFL);
305 if (fa < 0)
306 return -errno;
307
308 fb = fcntl(b, F_GETFL);
309 if (fb < 0)
310 return -errno;
311
312 return fa == fb;
313}
314
315void cmsg_close_all(struct msghdr *mh) {
316 struct cmsghdr *cmsg;
317
318 assert(mh);
319
320 CMSG_FOREACH(cmsg, mh)
321 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
322 close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
323}