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