1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "sd-daemon.h"
12 #include "alloc-util.h"
14 #include "bus-internal.h"
16 #include "errno-util.h"
19 #include "main-func.h"
21 #define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
23 static const char *arg_bus_path
= DEFAULT_BUS_PATH
;
24 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
25 static RuntimeScope arg_runtime_scope
= RUNTIME_SCOPE_SYSTEM
;
27 static int help(void) {
28 printf("%s [OPTIONS...]\n\n"
29 "Forward messages between a pipe or socket and a D-Bus bus.\n\n"
30 " -h --help Show this help\n"
31 " --version Show package version\n"
32 " -p --bus-path=PATH Path to the bus address (default: %s)\n"
33 " --system Connect to system bus\n"
34 " --user Connect to user bus\n"
35 " -M --machine=CONTAINER Name of local container to connect to\n",
36 program_invocation_short_name
, DEFAULT_BUS_PATH
);
41 static int parse_argv(int argc
, char *argv
[]) {
49 static const struct option options
[] = {
50 { "help", no_argument
, NULL
, 'h' },
51 { "version", no_argument
, NULL
, ARG_VERSION
},
52 { "bus-path", required_argument
, NULL
, 'p' },
53 { "user", no_argument
, NULL
, ARG_USER
},
54 { "system", no_argument
, NULL
, ARG_SYSTEM
},
55 { "machine", required_argument
, NULL
, 'M' },
64 while ((c
= getopt_long(argc
, argv
, "hp:M:", options
, NULL
)) >= 0)
75 arg_runtime_scope
= RUNTIME_SCOPE_USER
;
79 arg_runtime_scope
= RUNTIME_SCOPE_SYSTEM
;
83 arg_bus_path
= optarg
;
87 arg_bus_path
= optarg
;
88 arg_transport
= BUS_TRANSPORT_MACHINE
;
95 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
96 "Unknown option code %c", c
);
102 static int run(int argc
, char *argv
[]) {
103 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*a
= NULL
, *b
= NULL
;
104 sd_id128_t server_id
;
106 int r
, in_fd
, out_fd
;
108 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
109 log_parse_environment();
112 r
= parse_argv(argc
, argv
);
116 r
= sd_listen_fds(0);
118 in_fd
= STDIN_FILENO
;
119 out_fd
= STDOUT_FILENO
;
121 in_fd
= SD_LISTEN_FDS_START
;
122 out_fd
= SD_LISTEN_FDS_START
;
124 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "More than one file descriptor was passed.");
127 sd_is_socket(in_fd
, AF_UNIX
, 0, 0) > 0 &&
128 sd_is_socket(out_fd
, AF_UNIX
, 0, 0) > 0;
132 return log_error_errno(r
, "Failed to allocate bus: %m");
134 if (arg_transport
== BUS_TRANSPORT_MACHINE
)
135 r
= bus_set_address_machine(a
, arg_runtime_scope
, arg_bus_path
);
137 r
= sd_bus_set_address(a
, arg_bus_path
);
139 return log_error_errno(r
, "Failed to set address to connect to: %m");
141 r
= sd_bus_negotiate_fds(a
, is_unix
);
143 return log_error_errno(r
, "Failed to set FD negotiation: %m");
147 return log_error_errno(r
, "Failed to start bus client: %m");
149 r
= sd_bus_get_bus_id(a
, &server_id
);
151 return log_error_errno(r
, "Failed to get server ID: %m");
155 return log_error_errno(r
, "Failed to allocate bus: %m");
157 r
= sd_bus_set_fd(b
, in_fd
, out_fd
);
159 return log_error_errno(r
, "Failed to set fds: %m");
161 r
= sd_bus_set_server(b
, 1, server_id
);
163 return log_error_errno(r
, "Failed to set server mode: %m");
165 r
= sd_bus_negotiate_fds(b
, is_unix
);
167 return log_error_errno(r
, "Failed to set FD negotiation: %m");
169 r
= sd_bus_set_anonymous(b
, true);
171 return log_error_errno(r
, "Failed to set anonymous authentication: %m");
175 return log_error_errno(r
, "Failed to start bus client: %m");
178 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
179 int events_a
, events_b
, fd
;
180 usec_t timeout_a
, timeout_b
, t
;
182 assert_cc(sizeof(usec_t
) == sizeof(uint64_t));
184 r
= sd_bus_process(a
, &m
);
186 return log_error_errno(r
, "Failed to process bus a: %m");
189 r
= sd_bus_send(b
, m
, NULL
);
191 return log_error_errno(r
, "Failed to send message: %m");
197 r
= sd_bus_process(b
, &m
);
198 if (ERRNO_IS_NEG_DISCONNECT(r
))
199 /* Treat 'connection reset by peer' as clean exit condition */
202 return log_error_errno(r
, "Failed to process bus: %m");
205 r
= sd_bus_send(a
, m
, NULL
);
207 return log_error_errno(r
, "Failed to send message: %m");
213 fd
= sd_bus_get_fd(a
);
215 return log_error_errno(fd
, "Failed to get fd: %m");
217 events_a
= sd_bus_get_events(a
);
219 return log_error_errno(events_a
, "Failed to get events mask: %m");
221 r
= sd_bus_get_timeout(a
, &timeout_a
);
223 return log_error_errno(r
, "Failed to get timeout: %m");
225 events_b
= sd_bus_get_events(b
);
227 return log_error_errno(events_b
, "Failed to get events mask: %m");
229 r
= sd_bus_get_timeout(b
, &timeout_b
);
231 return log_error_errno(r
, "Failed to get timeout: %m");
233 t
= usec_sub_unsigned(MIN(timeout_a
, timeout_b
), now(CLOCK_MONOTONIC
));
235 struct pollfd p
[3] = {
236 { .fd
= fd
, .events
= events_a
},
237 { .fd
= STDIN_FILENO
, .events
= events_b
& POLLIN
},
238 { .fd
= STDOUT_FILENO
, .events
= events_b
& POLLOUT
},
241 r
= ppoll_usec(p
, ELEMENTSOF(p
), t
);
242 if (r
< 0 && !ERRNO_IS_TRANSIENT(r
)) /* don't be bothered by signals, i.e. EINTR */
243 return log_error_errno(r
, "ppoll() failed: %m");
249 DEFINE_MAIN_FUNCTION(run
);