]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fdset.c
Merge pull request #158 from ssahani/net
[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 if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
206 return r;
207
208 return 0;
209 }
210
211 int fdset_new_listen_fds(FDSet **_s, bool unset) {
212 int n, fd, r;
213 FDSet *s;
214
215 assert(_s);
216
217 /* Creates an fdset and fills in all passed file descriptors */
218
219 s = fdset_new();
220 if (!s) {
221 r = -ENOMEM;
222 goto fail;
223 }
224
225 n = sd_listen_fds(unset);
226 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
227 r = fdset_put(s, fd);
228 if (r < 0)
229 goto fail;
230 }
231
232 *_s = s;
233 return 0;
234
235
236 fail:
237 if (s)
238 set_free(MAKE_SET(s));
239
240 return r;
241 }
242
243 int fdset_close_others(FDSet *fds) {
244 void *e;
245 Iterator i;
246 int *a;
247 unsigned j, m;
248
249 j = 0, m = fdset_size(fds);
250 a = alloca(sizeof(int) * m);
251 SET_FOREACH(e, MAKE_SET(fds), i)
252 a[j++] = PTR_TO_FD(e);
253
254 assert(j == m);
255
256 return close_all_fds(a, j);
257 }
258
259 unsigned fdset_size(FDSet *fds) {
260 return set_size(MAKE_SET(fds));
261 }
262
263 bool fdset_isempty(FDSet *fds) {
264 return set_isempty(MAKE_SET(fds));
265 }
266
267 int fdset_iterate(FDSet *s, Iterator *i) {
268 void *p;
269
270 p = set_iterate(MAKE_SET(s), i);
271 if (!p)
272 return -ENOENT;
273
274 return PTR_TO_FD(p);
275 }
276
277 int fdset_steal_first(FDSet *fds) {
278 void *p;
279
280 p = set_steal_first(MAKE_SET(fds));
281 if (!p)
282 return -ENOENT;
283
284 return PTR_TO_FD(p);
285 }