]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/bus-proxyd.c
bus-proxy: turn into multi-threaded daemon
[thirdparty/systemd.git] / src / bus-proxyd / bus-proxyd.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 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
9 Copyright 2015 David Herrmann
10
11 systemd is free software; you can redistribute it and/or modify it
12 under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2.1 of the License, or
14 (at your option) any later version.
15
16 systemd is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 ***/
24
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/poll.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <pthread.h>
36
37 #include "log.h"
38 #include "util.h"
39 #include "hashmap.h"
40 #include "socket-util.h"
41 #include "sd-daemon.h"
42 #include "sd-bus.h"
43 #include "bus-internal.h"
44 #include "bus-message.h"
45 #include "bus-util.h"
46 #include "build.h"
47 #include "strv.h"
48 #include "def.h"
49 #include "capability.h"
50 #include "bus-control.h"
51 #include "smack-util.h"
52 #include "set.h"
53 #include "bus-xml-policy.h"
54 #include "driver.h"
55 #include "proxy.h"
56 #include "synthesize.h"
57
58 static char *arg_address = NULL;
59 static char **arg_configuration = NULL;
60
61 typedef struct {
62 int fd;
63 } ClientContext;
64
65 static ClientContext *client_context_free(ClientContext *c) {
66 if (!c)
67 return NULL;
68
69 close(c->fd);
70 free(c);
71
72 return NULL;
73 }
74
75 DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
76
77 static int client_context_new(ClientContext **out, int fd) {
78 _cleanup_(client_context_freep) ClientContext *c = NULL;
79
80 c = new0(ClientContext, 1);
81 if (!c)
82 return log_oom();
83
84 c->fd = fd;
85
86 *out = c;
87 c = NULL;
88 return 0;
89 }
90
91 static void *run_client(void *userdata) {
92 _cleanup_(client_context_freep) ClientContext *c = userdata;
93 _cleanup_(proxy_freep) Proxy *p = NULL;
94 int r;
95
96 r = proxy_new(&p, c->fd, c->fd, arg_address);
97 if (r < 0)
98 goto exit;
99
100 r = proxy_load_policy(p, arg_configuration);
101 if (r < 0)
102 goto exit;
103
104 r = proxy_hello_policy(p, getuid());
105 if (r < 0)
106 goto exit;
107
108 r = proxy_run(p);
109
110 exit:
111 return NULL;
112 }
113
114 static int loop_clients(int accept_fd) {
115 pthread_attr_t attr;
116 int r;
117
118 r = pthread_attr_init(&attr);
119 if (r < 0) {
120 r = log_error_errno(errno, "Cannot initialize pthread attributes: %m");
121 goto exit;
122 }
123
124 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
125 if (r < 0) {
126 r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
127 goto exit_attr;
128 }
129
130 for (;;) {
131 ClientContext *c;
132 pthread_t tid;
133 int fd;
134
135 fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
136 if (fd < 0) {
137 if (errno == EAGAIN || errno == EINTR)
138 continue;
139
140 r = log_error_errno(errno, "accept4() failed: %m");
141 break;
142 }
143
144 r = client_context_new(&c, fd);
145 if (r < 0) {
146 log_oom();
147 close(fd);
148 continue;
149 }
150
151 r = pthread_create(&tid, &attr, run_client, c);
152 if (r < 0) {
153 log_error("Cannot spawn thread: %m");
154 client_context_free(c);
155 continue;
156 }
157 }
158
159 exit_attr:
160 pthread_attr_destroy(&attr);
161 exit:
162 return r;
163 }
164
165 static int help(void) {
166
167 printf("%s [OPTIONS...]\n\n"
168 "DBus proxy server.\n\n"
169 " -h --help Show this help\n"
170 " --version Show package version\n"
171 " --configuration=PATH Configuration file or directory\n"
172 " --machine=MACHINE Connect to specified machine\n"
173 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
174 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
175 program_invocation_short_name);
176
177 return 0;
178 }
179
180 static int parse_argv(int argc, char *argv[]) {
181
182 enum {
183 ARG_VERSION = 0x100,
184 ARG_ADDRESS,
185 ARG_CONFIGURATION,
186 ARG_MACHINE,
187 };
188
189 static const struct option options[] = {
190 { "help", no_argument, NULL, 'h' },
191 { "version", no_argument, NULL, ARG_VERSION },
192 { "address", required_argument, NULL, ARG_ADDRESS },
193 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
194 { "machine", required_argument, NULL, ARG_MACHINE },
195 {},
196 };
197
198 int c, r;
199
200 assert(argc >= 0);
201 assert(argv);
202
203 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
204
205 switch (c) {
206
207 case 'h':
208 help();
209 return 0;
210
211 case ARG_VERSION:
212 puts(PACKAGE_STRING);
213 puts(SYSTEMD_FEATURES);
214 return 0;
215
216 case ARG_ADDRESS: {
217 char *a;
218
219 a = strdup(optarg);
220 if (!a)
221 return log_oom();
222
223 free(arg_address);
224 arg_address = a;
225 break;
226 }
227
228 case ARG_CONFIGURATION:
229 r = strv_extend(&arg_configuration, optarg);
230 if (r < 0)
231 return log_oom();
232 break;
233
234 case ARG_MACHINE: {
235 _cleanup_free_ char *e = NULL;
236 char *a;
237
238 e = bus_address_escape(optarg);
239 if (!e)
240 return log_oom();
241
242 #ifdef ENABLE_KDBUS
243 a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
244 #else
245 a = strjoin("x-machine-unix:machine=", e, NULL);
246 #endif
247 if (!a)
248 return log_oom();
249
250 free(arg_address);
251 arg_address = a;
252
253 break;
254 }
255
256 case '?':
257 return -EINVAL;
258
259 default:
260 assert_not_reached("Unhandled option");
261 }
262
263 if (argc > optind) {
264 log_error("Too many arguments");
265 return -EINVAL;
266 }
267
268 if (!arg_address) {
269 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
270 if (!arg_address)
271 return log_oom();
272 }
273
274 return 1;
275 }
276
277 int main(int argc, char *argv[]) {
278 int r, accept_fd;
279
280 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
281 log_parse_environment();
282 log_open();
283
284 r = parse_argv(argc, argv);
285 if (r <= 0)
286 goto finish;
287
288 r = sd_listen_fds(0);
289 if (r != 1) {
290 log_error("Illegal number of file descriptors passed");
291 goto finish;
292 }
293
294 accept_fd = SD_LISTEN_FDS_START;
295 r = fd_nonblock(accept_fd, false);
296 if (r < 0) {
297 log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
298 goto finish;
299 }
300
301 r = loop_clients(accept_fd);
302
303 finish:
304 sd_notify(false,
305 "STOPPING=1\n"
306 "STATUS=Shutting down.");
307
308 strv_free(arg_configuration);
309 free(arg_address);
310
311 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
312 }