]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/fdset.c
Merge pull request #4835 from poettering/unit-name-printf
[thirdparty/systemd.git] / src / shared / 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 <errno.h>
22 #include <fcntl.h>
23 #include <stddef.h>
24
25 #include "sd-daemon.h"
26
27 #include "dirent-util.h"
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_put_dup(FDSet *s, int fd) {
98 int copy, r;
99
100 assert(s);
101 assert(fd >= 0);
102
103 copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
104 if (copy < 0)
105 return -errno;
106
107 r = fdset_put(s, copy);
108 if (r < 0) {
109 safe_close(copy);
110 return r;
111 }
112
113 return copy;
114 }
115
116 bool fdset_contains(FDSet *s, int fd) {
117 assert(s);
118 assert(fd >= 0);
119
120 return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
121 }
122
123 int fdset_remove(FDSet *s, int fd) {
124 assert(s);
125 assert(fd >= 0);
126
127 return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
128 }
129
130 int fdset_new_fill(FDSet **_s) {
131 _cleanup_closedir_ DIR *d = NULL;
132 struct dirent *de;
133 int r = 0;
134 FDSet *s;
135
136 assert(_s);
137
138 /* Creates an fdset and fills in all currently open file
139 * descriptors. */
140
141 d = opendir("/proc/self/fd");
142 if (!d)
143 return -errno;
144
145 s = fdset_new();
146 if (!s) {
147 r = -ENOMEM;
148 goto finish;
149 }
150
151 FOREACH_DIRENT(de, d, return -errno) {
152 int fd = -1;
153
154 r = safe_atoi(de->d_name, &fd);
155 if (r < 0)
156 goto finish;
157
158 if (fd < 3)
159 continue;
160
161 if (fd == dirfd(d))
162 continue;
163
164 r = fdset_put(s, fd);
165 if (r < 0)
166 goto finish;
167 }
168
169 r = 0;
170 *_s = s;
171 s = NULL;
172
173 finish:
174 /* We won't close the fds here! */
175 if (s)
176 set_free(MAKE_SET(s));
177
178 return r;
179 }
180
181 int fdset_cloexec(FDSet *fds, bool b) {
182 Iterator i;
183 void *p;
184 int r;
185
186 assert(fds);
187
188 SET_FOREACH(p, MAKE_SET(fds), i) {
189 r = fd_cloexec(PTR_TO_FD(p), b);
190 if (r < 0)
191 return r;
192 }
193
194 return 0;
195 }
196
197 int fdset_new_listen_fds(FDSet **_s, bool unset) {
198 int n, fd, r;
199 FDSet *s;
200
201 assert(_s);
202
203 /* Creates an fdset and fills in all passed file descriptors */
204
205 s = fdset_new();
206 if (!s) {
207 r = -ENOMEM;
208 goto fail;
209 }
210
211 n = sd_listen_fds(unset);
212 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
213 r = fdset_put(s, fd);
214 if (r < 0)
215 goto fail;
216 }
217
218 *_s = s;
219 return 0;
220
221
222 fail:
223 if (s)
224 set_free(MAKE_SET(s));
225
226 return r;
227 }
228
229 int fdset_close_others(FDSet *fds) {
230 void *e;
231 Iterator i;
232 int *a;
233 unsigned j, m;
234
235 j = 0, m = fdset_size(fds);
236 a = alloca(sizeof(int) * m);
237 SET_FOREACH(e, MAKE_SET(fds), i)
238 a[j++] = PTR_TO_FD(e);
239
240 assert(j == m);
241
242 return close_all_fds(a, j);
243 }
244
245 unsigned fdset_size(FDSet *fds) {
246 return set_size(MAKE_SET(fds));
247 }
248
249 bool fdset_isempty(FDSet *fds) {
250 return set_isempty(MAKE_SET(fds));
251 }
252
253 int fdset_iterate(FDSet *s, Iterator *i) {
254 void *p;
255
256 if (!set_iterate(MAKE_SET(s), i, &p))
257 return -ENOENT;
258
259 return PTR_TO_FD(p);
260 }
261
262 int fdset_steal_first(FDSet *fds) {
263 void *p;
264
265 p = set_steal_first(MAKE_SET(fds));
266 if (!p)
267 return -ENOENT;
268
269 return PTR_TO_FD(p);
270 }