]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/fdset.c
util: replace close_nointr_nofail() by a more useful safe_close()
[thirdparty/systemd.git] / src / shared / fdset.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26
27 #include "set.h"
28 #include "util.h"
29 #include "macro.h"
30 #include "fdset.h"
31 #include "sd-daemon.h"
32
33 #define MAKE_SET(s) ((Set*) s)
34 #define MAKE_FDSET(s) ((FDSet*) s)
35
36 /* Make sure we can distuingish fd 0 and NULL */
37 #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
38 #define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
39
40 FDSet *fdset_new(void) {
41 return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func));
42 }
43
44 void fdset_free(FDSet *s) {
45 void *p;
46
47 while ((p = set_steal_first(MAKE_SET(s)))) {
48 /* Valgrind's fd might have ended up in this set here,
49 * due to fdset_new_fill(). We'll ignore all failures
50 * here, so that the EBADFD that valgrind will return
51 * us on close() doesn't influence us */
52
53 /* When reloading duplicates of the private bus
54 * connection fds and suchlike are closed here, which
55 * has no effect at all, since they are only
56 * duplicates. So don't be surprised about these log
57 * messages. */
58
59 log_debug("Closing left-over fd %i", PTR_TO_FD(p));
60 close_nointr(PTR_TO_FD(p));
61 }
62
63 set_free(MAKE_SET(s));
64 }
65
66 int fdset_put(FDSet *s, int fd) {
67 assert(s);
68 assert(fd >= 0);
69
70 return set_put(MAKE_SET(s), FD_TO_PTR(fd));
71 }
72
73 int fdset_put_dup(FDSet *s, int fd) {
74 int copy, r;
75
76 assert(s);
77 assert(fd >= 0);
78
79 copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
80 if (copy < 0)
81 return -errno;
82
83 r = fdset_put(s, copy);
84 if (r < 0) {
85 safe_close(copy);
86 return r;
87 }
88
89 return copy;
90 }
91
92 bool fdset_contains(FDSet *s, int fd) {
93 assert(s);
94 assert(fd >= 0);
95
96 return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
97 }
98
99 int fdset_remove(FDSet *s, int fd) {
100 assert(s);
101 assert(fd >= 0);
102
103 return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
104 }
105
106 int fdset_new_fill(FDSet **_s) {
107 DIR *d;
108 struct dirent *de;
109 int r = 0;
110 FDSet *s;
111
112 assert(_s);
113
114 /* Creates an fdset and fills in all currently open file
115 * descriptors. */
116
117 d = opendir("/proc/self/fd");
118 if (!d)
119 return -errno;
120
121 s = fdset_new();
122 if (!s) {
123 r = -ENOMEM;
124 goto finish;
125 }
126
127 while ((de = readdir(d))) {
128 int fd = -1;
129
130 if (ignore_file(de->d_name))
131 continue;
132
133 r = safe_atoi(de->d_name, &fd);
134 if (r < 0)
135 goto finish;
136
137 if (fd < 3)
138 continue;
139
140 if (fd == dirfd(d))
141 continue;
142
143 r = fdset_put(s, fd);
144 if (r < 0)
145 goto finish;
146 }
147
148 r = 0;
149 *_s = s;
150 s = NULL;
151
152 finish:
153 closedir(d);
154
155 /* We won't close the fds here! */
156 if (s)
157 set_free(MAKE_SET(s));
158
159 return r;
160 }
161
162 int fdset_cloexec(FDSet *fds, bool b) {
163 Iterator i;
164 void *p;
165 int r;
166
167 assert(fds);
168
169 SET_FOREACH(p, MAKE_SET(fds), i)
170 if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
171 return r;
172
173 return 0;
174 }
175
176 int fdset_new_listen_fds(FDSet **_s, bool unset) {
177 int n, fd, r;
178 FDSet *s;
179
180 assert(_s);
181
182 /* Creates an fdset and fills in all passed file descriptors */
183
184 s = fdset_new();
185 if (!s) {
186 r = -ENOMEM;
187 goto fail;
188 }
189
190 n = sd_listen_fds(unset);
191 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
192 r = fdset_put(s, fd);
193 if (r < 0)
194 goto fail;
195 }
196
197 *_s = s;
198 return 0;
199
200
201 fail:
202 if (s)
203 set_free(MAKE_SET(s));
204
205 return r;
206 }
207
208 int fdset_close_others(FDSet *fds) {
209 void *e;
210 Iterator i;
211 int *a;
212 unsigned j, m;
213
214 j = 0, m = fdset_size(fds);
215 a = alloca(sizeof(int) * m);
216 SET_FOREACH(e, MAKE_SET(fds), i)
217 a[j++] = PTR_TO_FD(e);
218
219 assert(j == m);
220
221 return close_all_fds(a, j);
222 }
223
224 unsigned fdset_size(FDSet *fds) {
225 return set_size(MAKE_SET(fds));
226 }
227
228 int fdset_iterate(FDSet *s, Iterator *i) {
229 void *p;
230
231 p = set_iterate(MAKE_SET(s), i);
232 if (!p)
233 return -ENOENT;
234
235 return PTR_TO_FD(p);
236 }