chiark / gitweb /
execute: support syscall filtering using seccomp filters
[elogind.git] / src / core / 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
32 #define MAKE_SET(s) ((Set*) s)
33 #define MAKE_FDSET(s) ((FDSet*) s)
34
35 /* Make sure we can distuingish fd 0 and NULL */
36 #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
37 #define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
38
39 FDSet *fdset_new(void) {
40         return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func));
41 }
42
43 void fdset_free(FDSet *s) {
44         void *p;
45
46         while ((p = set_steal_first(MAKE_SET(s)))) {
47                 /* Valgrind's fd might have ended up in this set here,
48                  * due to fdset_new_fill(). We'll ignore all failures
49                  * here, so that the EBADFD that valgrind will return
50                  * us on close() doesn't influence us */
51
52                 /* When reloading duplicates of the private bus
53                  * connection fds and suchlike are closed here, which
54                  * has no effect at all, since they are only
55                  * duplicates. So don't be surprised about these log
56                  * messages. */
57
58                 log_debug("Closing left-over fd %i", PTR_TO_FD(p));
59                 close_nointr(PTR_TO_FD(p));
60         }
61
62         set_free(MAKE_SET(s));
63 }
64
65 int fdset_put(FDSet *s, int fd) {
66         assert(s);
67         assert(fd >= 0);
68
69         return set_put(MAKE_SET(s), FD_TO_PTR(fd));
70 }
71
72 int fdset_put_dup(FDSet *s, int fd) {
73         int copy, r;
74
75         assert(s);
76         assert(fd >= 0);
77
78         if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
79                 return -errno;
80
81         if ((r = fdset_put(s, copy)) < 0) {
82                 close_nointr_nofail(copy);
83                 return r;
84         }
85
86         return copy;
87 }
88
89 bool fdset_contains(FDSet *s, int fd) {
90         assert(s);
91         assert(fd >= 0);
92
93         return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
94 }
95
96 int fdset_remove(FDSet *s, int fd) {
97         assert(s);
98         assert(fd >= 0);
99
100         return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
101 }
102
103 int fdset_new_fill(FDSet **_s) {
104         DIR *d;
105         struct dirent *de;
106         int r = 0;
107         FDSet *s;
108
109         assert(_s);
110
111         /* Creates an fdsets and fills in all currently open file
112          * descriptors. */
113
114         if (!(d = opendir("/proc/self/fd")))
115                 return -errno;
116
117         if (!(s = fdset_new())) {
118                 r = -ENOMEM;
119                 goto finish;
120         }
121
122         while ((de = readdir(d))) {
123                 int fd = -1;
124
125                 if (ignore_file(de->d_name))
126                         continue;
127
128                 if ((r = safe_atoi(de->d_name, &fd)) < 0)
129                         goto finish;
130
131                 if (fd < 3)
132                         continue;
133
134                 if (fd == dirfd(d))
135                         continue;
136
137                 if ((r = fdset_put(s, fd)) < 0)
138                         goto finish;
139         }
140
141         r = 0;
142         *_s = s;
143         s = NULL;
144
145 finish:
146         closedir(d);
147
148         /* We won't close the fds here! */
149         if (s)
150                 set_free(MAKE_SET(s));
151
152         return r;
153 }
154
155 int fdset_cloexec(FDSet *fds, bool b) {
156         Iterator i;
157         void *p;
158         int r;
159
160         assert(fds);
161
162         SET_FOREACH(p, MAKE_SET(fds), i)
163                 if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
164                         return r;
165
166         return 0;
167 }