1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
22 #include <sys/socket.h>
24 #include <sys/types.h>
35 #include "socket-util.h"
36 #include "sd-daemon.h"
38 #include "bus-internal.h"
39 #include "bus-message.h"
44 const char *arg_address = "kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket";
46 const char *arg_address = "unix:path=/run/dbus/system_bus_socket";
49 static int help(void) {
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);
61 static int parse_argv(int argc, char *argv[]) {
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 },
80 while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
90 puts(SYSTEMD_FEATURES);
101 assert_not_reached("Unhandled option");
108 int main(int argc, char *argv[]) {
109 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
110 sd_id128_t server_id;
112 int r, in_fd, out_fd;
114 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
115 log_parse_environment();
118 r = parse_argv(argc, argv);
122 r = sd_listen_fds(0);
124 in_fd = STDIN_FILENO;
125 out_fd = STDOUT_FILENO;
127 in_fd = SD_LISTEN_FDS_START;
128 out_fd = SD_LISTEN_FDS_START;
130 log_error("Illegal number of file descriptors passed\n");
135 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
136 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
140 log_error("Failed to allocate bus: %s", strerror(-r));
144 r = sd_bus_set_address(a, arg_address);
146 log_error("Failed to set address to connect to: %s", strerror(-r));
150 r = sd_bus_negotiate_fds(a, is_unix);
152 log_error("Failed to set FD negotiation: %s", strerror(-r));
158 log_error("Failed to start bus client: %s", strerror(-r));
162 r = sd_bus_get_server_id(a, &server_id);
164 log_error("Failed to get server ID: %s", strerror(-r));
170 log_error("Failed to allocate bus: %s", strerror(-r));
174 r = sd_bus_set_fd(b, in_fd, out_fd);
176 log_error("Failed to set fds: %s", strerror(-r));
180 r = sd_bus_set_server(b, 1, server_id);
182 log_error("Failed to set server mode: %s", strerror(-r));
186 r = sd_bus_negotiate_fds(b, is_unix);
188 log_error("Failed to set FD negotiation: %s", strerror(-r));
192 r = sd_bus_set_anonymous(b, true);
194 log_error("Failed to set anonymous authentication: %s", strerror(-r));
200 log_error("Failed to start bus client: %s", strerror(-r));
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;
210 r = sd_bus_process(a, &m);
212 /* treat 'connection reset by peer' as clean exit condition */
213 if (r == -ECONNRESET)
216 log_error("Failed to process bus a: %s", strerror(-r));
222 /* We officially got EOF, let's quit */
223 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
228 r = sd_bus_send(b, m, NULL);
230 log_error("Failed to send message: %s", strerror(-r));
238 r = sd_bus_process(b, &m);
240 /* treat 'connection reset by peer' as clean exit condition */
241 if (r == -ECONNRESET)
244 log_error("Failed to process bus b: %s", strerror(-r));
250 /* We officially got EOF, let's quit */
251 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
256 r = sd_bus_send(a, m, NULL);
258 log_error("Failed to send message: %s", strerror(-r));
266 fd = sd_bus_get_fd(a);
268 log_error("Failed to get fd: %s", strerror(-r));
272 events_a = sd_bus_get_events(a);
274 log_error("Failed to get events mask: %s", strerror(-r));
278 r = sd_bus_get_timeout(a, &timeout_a);
280 log_error("Failed to get timeout: %s", strerror(-r));
284 events_b = sd_bus_get_events(b);
286 log_error("Failed to get events mask: %s", strerror(-r));
290 r = sd_bus_get_timeout(b, &timeout_b);
292 log_error("Failed to get timeout: %s", strerror(-r));
297 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
300 if (t == (uint64_t) -1)
305 nw = now(CLOCK_MONOTONIC);
311 ts = timespec_store(&_ts, t);
315 struct pollfd p[3] = {
316 {.fd = fd, .events = events_a, },
317 {.fd = STDIN_FILENO, .events = events_b & POLLIN, },
318 {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
320 r = ppoll(p, ELEMENTSOF(p), ts, NULL);
323 log_error("ppoll() failed: %m");
334 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;