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