]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fdset.c
tree-wide: don't do assignments within if checks
[thirdparty/systemd.git] / src / basic / fdset.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 <errno.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25
26 #include "set.h"
27 #include "util.h"
28 #include "macro.h"
29 #include "fdset.h"
30 #include "sd-daemon.h"
31
32 #define MAKE_SET(s) ((Set*) s)
33 #define MAKE_FDSET(s) ((FDSet*) s)
34
35 /* Make sure we can distinguish fd 0 and NULL */
36 #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
37 #define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
38
39 FDSet *fdset_new(void) {
40 return MAKE_FDSET(set_new(NULL));
41 }
42
43 int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) {
44 unsigned i;
45 FDSet *s;
46 int r;
47
48 assert(ret);
49
50 s = fdset_new();
51 if (!s)
52 return -ENOMEM;
53
54 for (i = 0; i < n_fds; i++) {
55
56 r = fdset_put(s, fds[i]);
57 if (r < 0) {
58 set_free(MAKE_SET(s));
59 return r;
60 }
61 }
62
63 *ret = s;
64 return 0;
65 }
66
67 FDSet* fdset_free(FDSet *s) {
68 void *p;
69
70 while ((p = set_steal_first(MAKE_SET(s)))) {
71 /* Valgrind's fd might have ended up in this set here,
72 * due to fdset_new_fill(). We'll ignore all failures
73 * here, so that the EBADFD that valgrind will return
74 * us on close() doesn't influence us */
75
76 /* When reloading duplicates of the private bus
77 * connection fds and suchlike are closed here, which
78 * has no effect at all, since they are only
79 * duplicates. So don't be surprised about these log
80 * messages. */
81
82 log_debug("Closing left-over fd %i", PTR_TO_FD(p));
83 close_nointr(PTR_TO_FD(p));
84 }
85
86 set_free(MAKE_SET(s));
87 return NULL;
88 }
89
90 int fdset_put(FDSet *s, int fd) {
91 assert(s);
92 assert(fd >= 0);
93
94 return set_put(MAKE_SET(s), FD_TO_PTR(fd));
95 }
96
97 int fdset_consume(FDSet *s, int fd) {
98 int r;
99
100 assert(s);
101 assert(fd >= 0);
102
103 r = fdset_put(s, fd);
104 if (r <= 0)
105 safe_close(fd);
106
107 return r;
108 }
109
110 int fdset_put_dup(FDSet *s, int fd) {
111 int copy, r;
112
113 assert(s);
114 assert(fd >= 0);
115
116 copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
117 if (copy < 0)
118 return -errno;
119
120 r = fdset_put(s, copy);
121 if (r < 0) {
122 safe_close(copy);
123 return r;
124 }
125
126 return copy;
127 }
128
129 bool fdset_contains(FDSet *s, int fd) {
130 assert(s);
131 assert(fd >= 0);
132
133 return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
134 }
135
136 int fdset_remove(FDSet *s, int fd) {
137 assert(s);
138 assert(fd >= 0);
139
140 return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
141 }
142
143 int fdset_new_fill(FDSet **_s) {
144 _cleanup_closedir_ DIR *d = NULL;
145 struct dirent *de;
146 int r = 0;
147 FDSet *s;
148
149 assert(_s);
150
151 /* Creates an fdset and fills in all currently open file
152 * descriptors. */
153
154 d = opendir("/proc/self/fd");
155 if (!d)
156 return -errno;
157
158 s = fdset_new();
159 if (!s) {
160 r = -ENOMEM;
161 goto finish;
162 }
163
164 while ((de = readdir(d))) {
165 int fd = -1;
166
167 if (hidden_file(de->d_name))
168 continue;
169
170 r = safe_atoi(de->d_name, &fd);
171 if (r < 0)
172 goto finish;
173
174 if (fd < 3)
175 continue;
176
177 if (fd == dirfd(d))
178 continue;
179
180 r = fdset_put(s, fd);
181 if (r < 0)
182 goto finish;
183 }
184
185 r = 0;
186 *_s = s;
187 s = NULL;
188
189 finish:
190 /* We won't close the fds here! */
191 if (s)
192 set_free(MAKE_SET(s));
193
194 return r;
195 }
196
197 int fdset_cloexec(FDSet *fds, bool b) {
198 Iterator i;
199 void *p;
200 int r;
201
202 assert(fds);
203
204 SET_FOREACH(p, MAKE_SET(fds), i) {
205 r = fd_cloexec(PTR_TO_FD(p), b);
206 if (r < 0)
207 return r;
208 }
209
210 return 0;
211 }
212
213 int fdset_new_listen_fds(FDSet **_s, bool unset) {
214 int n, fd, r;
215 FDSet *s;
216
217 assert(_s);
218
219 /* Creates an fdset and fills in all passed file descriptors */
220
221 s = fdset_new();
222 if (!s) {
223 r = -ENOMEM;
224 goto fail;
225 }
226
227 n = sd_listen_fds(unset);
228 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
229 r = fdset_put(s, fd);
230 if (r < 0)
231 goto fail;
232 }
233
234 *_s = s;
235 return 0;
236
237
238 fail:
239 if (s)
240 set_free(MAKE_SET(s));
241
242 return r;
243 }
244
245 int fdset_close_others(FDSet *fds) {
246 void *e;
247 Iterator i;
248 int *a;
249 unsigned j, m;
250
251 j = 0, m = fdset_size(fds);
252 a = alloca(sizeof(int) * m);
253 SET_FOREACH(e, MAKE_SET(fds), i)
254 a[j++] = PTR_TO_FD(e);
255
256 assert(j == m);
257
258 return close_all_fds(a, j);
259 }
260
261 unsigned fdset_size(FDSet *fds) {
262 return set_size(MAKE_SET(fds));
263 }
264
265 bool fdset_isempty(FDSet *fds) {
266 return set_isempty(MAKE_SET(fds));
267 }
268
269 int fdset_iterate(FDSet *s, Iterator *i) {
270 void *p;
271
272 if (!set_iterate(MAKE_SET(s), i, &p))
273 return -ENOENT;
274
275 return PTR_TO_FD(p);
276 }
277
278 int fdset_steal_first(FDSet *fds) {
279 void *p;
280
281 p = set_steal_first(MAKE_SET(fds));
282 if (!p)
283 return -ENOENT;
284
285 return PTR_TO_FD(p);
286 }