]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fdset.c
selinux: use raw variants of security_compute_create and setfscreatecon
[thirdparty/systemd.git] / src / basic / 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 <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stddef.h>
25
26 #include "sd-daemon.h"
27
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 while ((de = readdir(d))) {
152 int fd = -1;
153
154 if (hidden_file(de->d_name))
155 continue;
156
157 r = safe_atoi(de->d_name, &fd);
158 if (r < 0)
159 goto finish;
160
161 if (fd < 3)
162 continue;
163
164 if (fd == dirfd(d))
165 continue;
166
167 r = fdset_put(s, fd);
168 if (r < 0)
169 goto finish;
170 }
171
172 r = 0;
173 *_s = s;
174 s = NULL;
175
176 finish:
177 /* We won't close the fds here! */
178 if (s)
179 set_free(MAKE_SET(s));
180
181 return r;
182 }
183
184 int fdset_cloexec(FDSet *fds, bool b) {
185 Iterator i;
186 void *p;
187 int r;
188
189 assert(fds);
190
191 SET_FOREACH(p, MAKE_SET(fds), i) {
192 r = fd_cloexec(PTR_TO_FD(p), b);
193 if (r < 0)
194 return r;
195 }
196
197 return 0;
198 }
199
200 int fdset_new_listen_fds(FDSet **_s, bool unset) {
201 int n, fd, r;
202 FDSet *s;
203
204 assert(_s);
205
206 /* Creates an fdset and fills in all passed file descriptors */
207
208 s = fdset_new();
209 if (!s) {
210 r = -ENOMEM;
211 goto fail;
212 }
213
214 n = sd_listen_fds(unset);
215 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
216 r = fdset_put(s, fd);
217 if (r < 0)
218 goto fail;
219 }
220
221 *_s = s;
222 return 0;
223
224
225 fail:
226 if (s)
227 set_free(MAKE_SET(s));
228
229 return r;
230 }
231
232 int fdset_close_others(FDSet *fds) {
233 void *e;
234 Iterator i;
235 int *a;
236 unsigned j, m;
237
238 j = 0, m = fdset_size(fds);
239 a = alloca(sizeof(int) * m);
240 SET_FOREACH(e, MAKE_SET(fds), i)
241 a[j++] = PTR_TO_FD(e);
242
243 assert(j == m);
244
245 return close_all_fds(a, j);
246 }
247
248 unsigned fdset_size(FDSet *fds) {
249 return set_size(MAKE_SET(fds));
250 }
251
252 bool fdset_isempty(FDSet *fds) {
253 return set_isempty(MAKE_SET(fds));
254 }
255
256 int fdset_iterate(FDSet *s, Iterator *i) {
257 void *p;
258
259 if (!set_iterate(MAKE_SET(s), i, &p))
260 return -ENOENT;
261
262 return PTR_TO_FD(p);
263 }
264
265 int fdset_steal_first(FDSet *fds) {
266 void *p;
267
268 p = set_steal_first(MAKE_SET(fds));
269 if (!p)
270 return -ENOENT;
271
272 return PTR_TO_FD(p);
273 }