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 #define UNIX_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
45 #define KERNEL_BUS_PATH "kernel:path=/dev/kdbus/0-system/bus"
48 # define DEFAULT_BUS_PATH KERNEL_BUS_PATH ";" UNIX_BUS_PATH
50 # define DEFAULT_BUS_PATH UNIX_BUS_PATH
53 static const char *arg_address = DEFAULT_BUS_PATH;
54 static char *arg_command_line_buffer = NULL;
56 static int help(void) {
58 printf("%s [OPTIONS...]\n\n"
59 "Connect STDIO or a socket to a given bus address.\n\n"
60 " -h --help Show this help\n"
61 " --version Show package version\n"
62 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
63 " (default: " DEFAULT_BUS_PATH ")\n",
64 program_invocation_short_name);
69 static int parse_argv(int argc, char *argv[]) {
76 static const struct option options[] = {
77 { "help", no_argument, NULL, 'h' },
78 { "version", no_argument, NULL, ARG_VERSION },
79 { "address", required_argument, NULL, ARG_ADDRESS },
88 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
98 puts(SYSTEMD_FEATURES);
102 arg_address = optarg;
109 assert_not_reached("Unhandled option");
113 /* If the first command line argument is only "x" characters
114 * we'll write who we are talking to into it, so that "ps" is
116 arg_command_line_buffer = argv[optind];
117 if (argc > optind + 1 ||
118 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
119 log_error("Too many arguments");
126 int main(int argc, char *argv[]) {
128 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
129 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
130 sd_id128_t server_id;
131 int r, in_fd, out_fd;
138 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
139 log_parse_environment();
142 r = parse_argv(argc, argv);
146 r = sd_listen_fds(0);
148 in_fd = STDIN_FILENO;
149 out_fd = STDOUT_FILENO;
151 in_fd = SD_LISTEN_FDS_START;
152 out_fd = SD_LISTEN_FDS_START;
154 log_error("Illegal number of file descriptors passed\n");
159 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
160 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
164 log_error("Failed to allocate bus: %s", strerror(-r));
168 r = sd_bus_set_address(a, arg_address);
170 log_error("Failed to set address to connect to: %s", strerror(-r));
174 r = sd_bus_negotiate_fds(a, is_unix);
176 log_error("Failed to set FD negotiation: %s", strerror(-r));
182 log_error("Failed to start bus client: %s", strerror(-r));
186 r = sd_bus_get_server_id(a, &server_id);
188 log_error("Failed to get server ID: %s", strerror(-r));
194 log_error("Failed to allocate bus: %s", strerror(-r));
198 r = sd_bus_set_fd(b, in_fd, out_fd);
200 log_error("Failed to set fds: %s", strerror(-r));
204 r = sd_bus_set_server(b, 1, server_id);
206 log_error("Failed to set server mode: %s", strerror(-r));
210 r = sd_bus_negotiate_fds(b, is_unix);
212 log_error("Failed to set FD negotiation: %s", strerror(-r));
216 r = sd_bus_set_anonymous(b, true);
218 log_error("Failed to set anonymous authentication: %s", strerror(-r));
224 log_error("Failed to start bus client: %s", strerror(-r));
228 if (sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds) >= 0 &&
229 sd_bus_creds_get_uid(creds, &uid) >= 0 &&
230 sd_bus_creds_get_pid(creds, &pid) >= 0 &&
231 sd_bus_creds_get_cmdline(creds, &cmdline) >= 0 &&
232 sd_bus_creds_get_comm(creds, &comm) >= 0) {
233 _cleanup_free_ char *p = NULL, *name = NULL;
235 name = uid_to_name(uid);
241 p = strv_join(cmdline, " ");
247 /* The status string gets the full command line ... */
249 "STATUS=Processing requests from client PID %lu (%s); UID %lu (%s)",
250 (unsigned long) pid, p,
251 (unsigned long) uid, name);
253 /* ... and the argv line only the short comm */
254 if (arg_command_line_buffer) {
257 m = strlen(arg_command_line_buffer);
258 w = snprintf(arg_command_line_buffer, m,
259 "[PID %lu/%s; UID %lu/%s]",
260 (unsigned long) pid, comm,
261 (unsigned long) uid, name);
264 memset(arg_command_line_buffer + w, 0, m - w);
270 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
271 int events_a, events_b, fd;
272 uint64_t timeout_a, timeout_b, t;
273 struct timespec _ts, *ts;
274 struct pollfd *pollfd;
277 r = sd_bus_process(a, &m);
279 /* treat 'connection reset by peer' as clean exit condition */
280 if (r == -ECONNRESET)
283 log_error("Failed to process bus a: %s", strerror(-r));
289 /* We officially got EOF, let's quit */
290 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
295 k = sd_bus_send(b, m, NULL);
298 log_error("Failed to send message: %s", strerror(-r));
306 r = sd_bus_process(b, &m);
308 /* treat 'connection reset by peer' as clean exit condition */
309 if (r == -ECONNRESET)
312 log_error("Failed to process bus b: %s", strerror(-r));
318 /* We officially got EOF, let's quit */
319 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
324 k = sd_bus_send(a, m, NULL);
327 log_error("Failed to send message: %s", strerror(-r));
335 fd = sd_bus_get_fd(a);
337 log_error("Failed to get fd: %s", strerror(-r));
341 events_a = sd_bus_get_events(a);
343 log_error("Failed to get events mask: %s", strerror(-r));
347 r = sd_bus_get_timeout(a, &timeout_a);
349 log_error("Failed to get timeout: %s", strerror(-r));
353 events_b = sd_bus_get_events(b);
355 log_error("Failed to get events mask: %s", strerror(-r));
359 r = sd_bus_get_timeout(b, &timeout_b);
361 log_error("Failed to get timeout: %s", strerror(-r));
366 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
369 if (t == (uint64_t) -1)
374 nw = now(CLOCK_MONOTONIC);
380 ts = timespec_store(&_ts, t);
383 pollfd = (struct pollfd[3]) {
384 {.fd = fd, .events = events_a, },
385 {.fd = in_fd, .events = events_b & POLLIN, },
386 {.fd = out_fd, .events = events_b & POLLOUT, }
389 r = ppoll(pollfd, 3, ts, NULL);
391 log_error("ppoll() failed: %m");
402 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;