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;
272 struct timespec _ts, *ts;
273 struct pollfd *pollfd;
286 for (i = 0; i < 2; i ++) {
287 r = sd_bus_process(busses[i].bus, &m);
289 /* treat 'connection reset by peer' as clean exit condition */
290 if (r == -ECONNRESET)
293 log_error("Failed to process bus %s: %s",
294 busses[i].name, strerror(-r));
299 /* We officially got EOF, let's quit */
300 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
305 k = sd_bus_send(busses[1-i].bus, m, NULL);
308 log_error("Failed to send message to bus %s: %s",
309 busses[1-i].name, strerror(-r));
318 fd = sd_bus_get_fd(a);
320 log_error("Failed to get fd: %s", strerror(-r));
324 for (i = 0; i < 2; i ++) {
325 busses[i].events = sd_bus_get_events(a);
326 if (busses[i].events < 0) {
327 log_error("Failed to get events mask: %s", strerror(-r));
331 r = sd_bus_get_timeout(a, &busses[i].timeout);
333 log_error("Failed to get timeout: %s", strerror(-r));
338 t = busses[0].timeout;
339 if (t == (uint64_t) -1 ||
340 (busses[1].timeout != (uint64_t) -1 && busses[1].timeout < t))
341 t = busses[1].timeout;
343 if (t == (uint64_t) -1)
348 nw = now(CLOCK_MONOTONIC);
354 ts = timespec_store(&_ts, t);
357 pollfd = (struct pollfd[3]) {
358 {.fd = fd, .events = busses[0].events },
359 {.fd = in_fd, .events = busses[1].events & POLLIN },
360 {.fd = out_fd, .events = busses[1].events & POLLOUT },
363 r = ppoll(pollfd, 3, ts, NULL);
365 log_error("ppoll() failed: %m");
376 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;