]> git.proxmox.com Git - systemd.git/blob - src/basic/fdset.c
Merge tag 'upstream/229'
[systemd.git] / src / basic / fdset.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <alloca.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stddef.h>
25
26 #include "sd-daemon.h"
27
28 #include "fd-util.h"
29 #include "fdset.h"
30 #include "log.h"
31 #include "macro.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "set.h"
35
36 #define MAKE_SET(s) ((Set*) s)
37 #define MAKE_FDSET(s) ((FDSet*) s)
38
39 FDSet *fdset_new(void) {
40 return MAKE_FDSET(set_new(NULL));
41 }
42
43 int fdset_new_array(FDSet **ret, const 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 }