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