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 9 : FDSet *fdset_new(void) {
24 9 : return MAKE_FDSET(set_new(NULL));
25 : }
26 :
27 1 : 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 1 : assert(ret);
33 :
34 1 : s = fdset_new();
35 1 : if (!s)
36 0 : return -ENOMEM;
37 :
38 5 : for (i = 0; i < n_fds; i++) {
39 :
40 4 : r = fdset_put(s, fds[i]);
41 4 : if (r < 0) {
42 0 : set_free(MAKE_SET(s));
43 0 : return r;
44 : }
45 : }
46 :
47 1 : *ret = s;
48 1 : return 0;
49 : }
50 :
51 9 : void fdset_close(FDSet *s) {
52 : void *p;
53 :
54 20 : 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 11 : log_debug("Closing set fd %i", PTR_TO_FD(p));
64 11 : (void) close_nointr(PTR_TO_FD(p));
65 : }
66 9 : }
67 :
68 9 : FDSet* fdset_free(FDSet *s) {
69 9 : fdset_close(s);
70 9 : set_free(MAKE_SET(s));
71 9 : return NULL;
72 : }
73 :
74 15 : int fdset_put(FDSet *s, int fd) {
75 15 : assert(s);
76 15 : assert(fd >= 0);
77 :
78 15 : return set_put(MAKE_SET(s), FD_TO_PTR(fd));
79 : }
80 :
81 2 : int fdset_put_dup(FDSet *s, int fd) {
82 : int copy, r;
83 :
84 2 : assert(s);
85 2 : assert(fd >= 0);
86 :
87 2 : copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
88 2 : if (copy < 0)
89 0 : return -errno;
90 :
91 2 : r = fdset_put(s, copy);
92 2 : if (r < 0) {
93 0 : safe_close(copy);
94 0 : return r;
95 : }
96 :
97 2 : return copy;
98 : }
99 :
100 8 : bool fdset_contains(FDSet *s, int fd) {
101 8 : assert(s);
102 8 : assert(fd >= 0);
103 :
104 8 : return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
105 : }
106 :
107 1 : int fdset_remove(FDSet *s, int fd) {
108 1 : assert(s);
109 1 : assert(fd >= 0);
110 :
111 1 : return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
112 : }
113 :
114 1 : int fdset_new_fill(FDSet **_s) {
115 1 : _cleanup_closedir_ DIR *d = NULL;
116 : struct dirent *de;
117 1 : int r = 0;
118 : FDSet *s;
119 :
120 1 : assert(_s);
121 :
122 : /* Creates an fdset and fills in all currently open file
123 : * descriptors. */
124 :
125 1 : d = opendir("/proc/self/fd");
126 1 : if (!d)
127 0 : return -errno;
128 :
129 1 : s = fdset_new();
130 1 : if (!s) {
131 0 : r = -ENOMEM;
132 0 : goto finish;
133 : }
134 :
135 8 : FOREACH_DIRENT(de, d, return -errno) {
136 5 : int fd = -1;
137 :
138 5 : r = safe_atoi(de->d_name, &fd);
139 5 : if (r < 0)
140 0 : goto finish;
141 :
142 5 : if (fd < 3)
143 4 : continue;
144 :
145 2 : if (fd == dirfd(d))
146 1 : continue;
147 :
148 1 : r = fdset_put(s, fd);
149 1 : if (r < 0)
150 0 : goto finish;
151 : }
152 :
153 1 : r = 0;
154 1 : *_s = TAKE_PTR(s);
155 :
156 1 : finish:
157 : /* We won't close the fds here! */
158 1 : if (s)
159 0 : set_free(MAKE_SET(s));
160 :
161 1 : return r;
162 : }
163 :
164 2 : int fdset_cloexec(FDSet *fds, bool b) {
165 : Iterator i;
166 : void *p;
167 : int r;
168 :
169 2 : assert(fds);
170 :
171 4 : SET_FOREACH(p, MAKE_SET(fds), i) {
172 2 : r = fd_cloexec(PTR_TO_FD(p), b);
173 2 : if (r < 0)
174 0 : return r;
175 : }
176 :
177 2 : 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 1 : int fdset_close_others(FDSet *fds) {
212 : void *e;
213 : Iterator i;
214 1 : int *a = NULL;
215 1 : size_t j = 0, m;
216 :
217 1 : m = fdset_size(fds);
218 :
219 1 : if (m > 0) {
220 1 : a = newa(int, m);
221 2 : SET_FOREACH(e, MAKE_SET(fds), i)
222 1 : a[j++] = PTR_TO_FD(e);
223 : }
224 :
225 1 : assert(j == m);
226 :
227 1 : return close_all_fds(a, j);
228 : }
229 :
230 13 : unsigned fdset_size(FDSet *fds) {
231 13 : return set_size(MAKE_SET(fds));
232 : }
233 :
234 2 : bool fdset_isempty(FDSet *fds) {
235 2 : return set_isempty(MAKE_SET(fds));
236 : }
237 :
238 2 : int fdset_iterate(FDSet *s, Iterator *i) {
239 : void *p;
240 :
241 2 : if (!set_iterate(MAKE_SET(s), i, &p))
242 1 : return -ENOENT;
243 :
244 1 : return PTR_TO_FD(p);
245 : }
246 :
247 3 : int fdset_steal_first(FDSet *fds) {
248 : void *p;
249 :
250 3 : p = set_steal_first(MAKE_SET(fds));
251 3 : if (!p)
252 2 : return -ENOENT;
253 :
254 1 : return PTR_TO_FD(p);
255 : }
|