]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/bus-proxyd.c
bus: change bus-proxyd command line parsing to be more similar to other tools
[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
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 <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/poll.h>
30 #include <stddef.h>
31 #include <getopt.h>
32
33 #include "log.h"
34 #include "util.h"
35 #include "socket-util.h"
36 #include "sd-daemon.h"
37 #include "sd-bus.h"
38 #include "bus-internal.h"
39 #include "bus-message.h"
40 #include "bus-util.h"
41 #include "build.h"
42
43 #ifdef ENABLE_KDBUS
44 const char *arg_address = "kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket";
45 #else
46 const char *arg_address = "unix:path=/run/dbus/system_bus_socket";
47 #endif
48
49 static int help(void) {
50
51 printf("%s [OPTIONS...]\n\n"
52 "Connect STDIO or a socket to a given bus address.\n\n"
53 " -h --help Show this help\n"
54 " --version Show package version\n"
55 " --address=ADDRESS Connect to bus specified by address\n",
56 program_invocation_short_name);
57
58 return 0;
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63 enum {
64 ARG_VERSION = 0x100,
65 ARG_ADDRESS,
66 };
67
68 static const struct option options[] = {
69 { "help", no_argument, NULL, 'h' },
70 { "version", no_argument, NULL, ARG_VERSION },
71 { "address", required_argument, NULL, ARG_ADDRESS },
72 { NULL, 0, NULL, 0 }
73 };
74
75 int c;
76
77 assert(argc >= 0);
78 assert(argv);
79
80 while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
81
82 switch (c) {
83
84 case 'h':
85 help();
86 return 0;
87
88 case ARG_VERSION:
89 puts(PACKAGE_STRING);
90 puts(SYSTEMD_FEATURES);
91 return 0;
92
93 case ARG_ADDRESS:
94 arg_address = optarg;
95 break;
96
97 case '?':
98 return -EINVAL;
99
100 default:
101 assert_not_reached("Unhandled option");
102 }
103 }
104
105 return 1;
106 }
107
108 int main(int argc, char *argv[]) {
109 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
110 sd_id128_t server_id;
111 bool is_unix;
112 int r, in_fd, out_fd;
113
114 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
115 log_parse_environment();
116 log_open();
117
118 r = parse_argv(argc, argv);
119 if (r <= 0)
120 goto finish;
121
122 r = sd_listen_fds(0);
123 if (r == 0) {
124 in_fd = STDIN_FILENO;
125 out_fd = STDOUT_FILENO;
126 } else if (r == 1) {
127 in_fd = SD_LISTEN_FDS_START;
128 out_fd = SD_LISTEN_FDS_START;
129 } else {
130 log_error("Illegal number of file descriptors passed\n");
131 goto finish;
132 }
133
134 is_unix =
135 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
136 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
137
138 r = sd_bus_new(&a);
139 if (r < 0) {
140 log_error("Failed to allocate bus: %s", strerror(-r));
141 goto finish;
142 }
143
144 r = sd_bus_set_address(a, arg_address);
145 if (r < 0) {
146 log_error("Failed to set address to connect to: %s", strerror(-r));
147 goto finish;
148 }
149
150 r = sd_bus_negotiate_fds(a, is_unix);
151 if (r < 0) {
152 log_error("Failed to set FD negotiation: %s", strerror(-r));
153 goto finish;
154 }
155
156 r = sd_bus_start(a);
157 if (r < 0) {
158 log_error("Failed to start bus client: %s", strerror(-r));
159 goto finish;
160 }
161
162 r = sd_bus_get_server_id(a, &server_id);
163 if (r < 0) {
164 log_error("Failed to get server ID: %s", strerror(-r));
165 goto finish;
166 }
167
168 r = sd_bus_new(&b);
169 if (r < 0) {
170 log_error("Failed to allocate bus: %s", strerror(-r));
171 goto finish;
172 }
173
174 r = sd_bus_set_fd(b, in_fd, out_fd);
175 if (r < 0) {
176 log_error("Failed to set fds: %s", strerror(-r));
177 goto finish;
178 }
179
180 r = sd_bus_set_server(b, 1, server_id);
181 if (r < 0) {
182 log_error("Failed to set server mode: %s", strerror(-r));
183 goto finish;
184 }
185
186 r = sd_bus_negotiate_fds(b, is_unix);
187 if (r < 0) {
188 log_error("Failed to set FD negotiation: %s", strerror(-r));
189 goto finish;
190 }
191
192 r = sd_bus_set_anonymous(b, true);
193 if (r < 0) {
194 log_error("Failed to set anonymous authentication: %s", strerror(-r));
195 goto finish;
196 }
197
198 r = sd_bus_start(b);
199 if (r < 0) {
200 log_error("Failed to start bus client: %s", strerror(-r));
201 goto finish;
202 }
203
204 for (;;) {
205 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
206 int events_a, events_b, fd;
207 uint64_t timeout_a, timeout_b, t;
208 struct timespec _ts, *ts;
209
210 r = sd_bus_process(a, &m);
211 if (r < 0) {
212 log_error("Failed to process bus a: %s", strerror(-r));
213 goto finish;
214 }
215
216 if (m) {
217 r = sd_bus_send(b, m, NULL);
218 if (r < 0) {
219 log_error("Failed to send message: %s", strerror(-r));
220 goto finish;
221 }
222 }
223
224 if (r > 0)
225 continue;
226
227 r = sd_bus_process(b, &m);
228 if (r < 0) {
229 /* treat 'connection reset by peer' as clean exit condition */
230 if (r == -ECONNRESET)
231 r = 0;
232
233 goto finish;
234 }
235
236 if (m) {
237 r = sd_bus_send(a, m, NULL);
238 if (r < 0) {
239 log_error("Failed to send message: %s", strerror(-r));
240 goto finish;
241 }
242 }
243
244 if (r > 0)
245 continue;
246
247 fd = sd_bus_get_fd(a);
248 if (fd < 0) {
249 log_error("Failed to get fd: %s", strerror(-r));
250 goto finish;
251 }
252
253 events_a = sd_bus_get_events(a);
254 if (events_a < 0) {
255 log_error("Failed to get events mask: %s", strerror(-r));
256 goto finish;
257 }
258
259 r = sd_bus_get_timeout(a, &timeout_a);
260 if (r < 0) {
261 log_error("Failed to get timeout: %s", strerror(-r));
262 goto finish;
263 }
264
265 events_b = sd_bus_get_events(b);
266 if (events_b < 0) {
267 log_error("Failed to get events mask: %s", strerror(-r));
268 goto finish;
269 }
270
271 r = sd_bus_get_timeout(b, &timeout_b);
272 if (r < 0) {
273 log_error("Failed to get timeout: %s", strerror(-r));
274 goto finish;
275 }
276
277 t = timeout_a;
278 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
279 t = timeout_b;
280
281 if (t == (uint64_t) -1)
282 ts = NULL;
283 else {
284 usec_t nw;
285
286 nw = now(CLOCK_MONOTONIC);
287 if (t > nw)
288 t -= nw;
289 else
290 t = 0;
291
292 ts = timespec_store(&_ts, t);
293 }
294
295 {
296 struct pollfd p[3] = {
297 {.fd = fd, .events = events_a, },
298 {.fd = STDIN_FILENO, .events = events_b & POLLIN, },
299 {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
300
301 r = ppoll(p, ELEMENTSOF(p), ts, NULL);
302 }
303 if (r < 0) {
304 log_error("ppoll() failed: %m");
305 goto finish;
306 }
307 }
308
309 r = 0;
310
311 finish:
312 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
313 }