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