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"
45 static const char *arg_address = "kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket";
47 static const char *arg_address = "unix:path=/run/dbus/system_bus_socket";
50 static char *arg_command_line_buffer = NULL;
52 static int help(void) {
54 printf("%s [OPTIONS...]\n\n"
55 "Connect STDIO or a socket to a given bus address.\n\n"
56 " -h --help Show this help\n"
57 " --version Show package version\n"
58 " --address=ADDRESS Connect to bus specified by address\n",
59 program_invocation_short_name);
64 static int parse_argv(int argc, char *argv[]) {
71 static const struct option options[] = {
72 { "help", no_argument, NULL, 'h' },
73 { "version", no_argument, NULL, ARG_VERSION },
74 { "address", required_argument, NULL, ARG_ADDRESS },
83 while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
93 puts(SYSTEMD_FEATURES);
104 assert_not_reached("Unhandled option");
108 /* If the first command line argument is only "x" characters
109 * we'll write who we are talking to into it, so that "ps" is
111 arg_command_line_buffer = argv[optind];
112 if (argc > optind + 1 ||
113 (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
114 log_error("Too many arguments");
121 int main(int argc, char *argv[]) {
123 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
124 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
125 sd_id128_t server_id;
126 int r, in_fd, out_fd;
133 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
134 log_parse_environment();
137 r = parse_argv(argc, argv);
141 r = sd_listen_fds(0);
143 in_fd = STDIN_FILENO;
144 out_fd = STDOUT_FILENO;
146 in_fd = SD_LISTEN_FDS_START;
147 out_fd = SD_LISTEN_FDS_START;
149 log_error("Illegal number of file descriptors passed\n");
154 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
155 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
159 log_error("Failed to allocate bus: %s", strerror(-r));
163 r = sd_bus_set_address(a, arg_address);
165 log_error("Failed to set address to connect to: %s", strerror(-r));
169 r = sd_bus_negotiate_fds(a, is_unix);
171 log_error("Failed to set FD negotiation: %s", strerror(-r));
177 log_error("Failed to start bus client: %s", strerror(-r));
181 r = sd_bus_get_server_id(a, &server_id);
183 log_error("Failed to get server ID: %s", strerror(-r));
189 log_error("Failed to allocate bus: %s", strerror(-r));
193 r = sd_bus_set_fd(b, in_fd, out_fd);
195 log_error("Failed to set fds: %s", strerror(-r));
199 r = sd_bus_set_server(b, 1, server_id);
201 log_error("Failed to set server mode: %s", strerror(-r));
205 r = sd_bus_negotiate_fds(b, is_unix);
207 log_error("Failed to set FD negotiation: %s", strerror(-r));
211 r = sd_bus_set_anonymous(b, true);
213 log_error("Failed to set anonymous authentication: %s", strerror(-r));
219 log_error("Failed to start bus client: %s", strerror(-r));
223 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 &&
224 sd_bus_creds_get_uid(creds, &uid) >= 0 &&
225 sd_bus_creds_get_pid(creds, &pid) >= 0 &&
226 sd_bus_creds_get_cmdline(creds, &cmdline) >= 0 &&
227 sd_bus_creds_get_comm(creds, &comm) >= 0) {
228 _cleanup_free_ char *p = NULL, *name = NULL;
230 name = uid_to_name(uid);
236 p = strv_join(cmdline, " ");
242 /* The status string gets the full command line ... */
244 "STATUS=Processing requests from client PID %lu (%s); UID %lu (%s)",
245 (unsigned long) pid, p,
246 (unsigned long) uid, name);
248 /* ... and the argv line only the short comm */
249 if (arg_command_line_buffer) {
252 m = strlen(arg_command_line_buffer);
253 w = snprintf(arg_command_line_buffer, m,
254 "[PID %lu/%s; UID %lu/%s]",
255 (unsigned long) pid, comm,
256 (unsigned long) uid, name);
259 memset(arg_command_line_buffer + w, 0, m - w);
265 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
266 int events_a, events_b, fd;
267 uint64_t timeout_a, timeout_b, t;
268 struct timespec _ts, *ts;
269 struct pollfd *pollfd;
272 r = sd_bus_process(a, &m);
274 /* treat 'connection reset by peer' as clean exit condition */
275 if (r == -ECONNRESET)
278 log_error("Failed to process bus a: %s", strerror(-r));
284 /* We officially got EOF, let's quit */
285 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
290 k = sd_bus_send(b, m, NULL);
293 log_error("Failed to send message: %s", strerror(-r));
301 r = sd_bus_process(b, &m);
303 /* treat 'connection reset by peer' as clean exit condition */
304 if (r == -ECONNRESET)
307 log_error("Failed to process bus b: %s", strerror(-r));
313 /* We officially got EOF, let's quit */
314 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
319 k = sd_bus_send(a, m, NULL);
322 log_error("Failed to send message: %s", strerror(-r));
330 fd = sd_bus_get_fd(a);
332 log_error("Failed to get fd: %s", strerror(-r));
336 events_a = sd_bus_get_events(a);
338 log_error("Failed to get events mask: %s", strerror(-r));
342 r = sd_bus_get_timeout(a, &timeout_a);
344 log_error("Failed to get timeout: %s", strerror(-r));
348 events_b = sd_bus_get_events(b);
350 log_error("Failed to get events mask: %s", strerror(-r));
354 r = sd_bus_get_timeout(b, &timeout_b);
356 log_error("Failed to get timeout: %s", strerror(-r));
361 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
364 if (t == (uint64_t) -1)
369 nw = now(CLOCK_MONOTONIC);
375 ts = timespec_store(&_ts, t);
378 pollfd = (struct pollfd[3]) {
379 {.fd = fd, .events = events_a, },
380 {.fd = in_fd, .events = events_b & POLLIN, },
381 {.fd = out_fd, .events = events_b & POLLOUT, }
384 r = ppoll(pollfd, 3, ts, NULL);
386 log_error("ppoll() failed: %m");
397 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;