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