]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
798c486f DM |
2 | |
3 | #include <errno.h> | |
4 | #include <getopt.h> | |
798c486f DM |
5 | #include <stddef.h> |
6 | #include <string.h> | |
7 | #include <unistd.h> | |
8 | ||
9 | #include "sd-bus.h" | |
10 | #include "sd-daemon.h" | |
11 | ||
19df1528 | 12 | #include "alloc-util.h" |
d6b4d1c7 | 13 | #include "build.h" |
798c486f DM |
14 | #include "bus-internal.h" |
15 | #include "bus-util.h" | |
4e17e5c2 | 16 | #include "errno-util.h" |
d9e2af0a | 17 | #include "io-util.h" |
798c486f | 18 | #include "log.h" |
5e332028 | 19 | #include "main-func.h" |
798c486f DM |
20 | |
21 | #define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" | |
22 | ||
19df1528 SL |
23 | static const char *arg_bus_path = DEFAULT_BUS_PATH; |
24 | static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; | |
4870133b | 25 | static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; |
798c486f DM |
26 | |
27 | static int help(void) { | |
798c486f | 28 | printf("%s [OPTIONS...]\n\n" |
a2012854 | 29 | "Forward messages between a pipe or socket and a D-Bus bus.\n\n" |
798c486f DM |
30 | " -h --help Show this help\n" |
31 | " --version Show package version\n" | |
cedfd142 LP |
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", | |
798c486f DM |
36 | program_invocation_short_name, DEFAULT_BUS_PATH); |
37 | ||
38 | return 0; | |
39 | } | |
40 | ||
41 | static int parse_argv(int argc, char *argv[]) { | |
798c486f DM |
42 | enum { |
43 | ARG_VERSION = 0x100, | |
19df1528 | 44 | ARG_MACHINE, |
cedfd142 LP |
45 | ARG_USER, |
46 | ARG_SYSTEM, | |
798c486f DM |
47 | }; |
48 | ||
49 | static const struct option options[] = { | |
8b2c2abc YW |
50 | { "help", no_argument, NULL, 'h' }, |
51 | { "version", no_argument, NULL, ARG_VERSION }, | |
52 | { "bus-path", required_argument, NULL, 'p' }, | |
cedfd142 LP |
53 | { "user", no_argument, NULL, ARG_USER }, |
54 | { "system", no_argument, NULL, ARG_SYSTEM }, | |
19df1528 | 55 | { "machine", required_argument, NULL, 'M' }, |
8b2c2abc | 56 | {}, |
798c486f DM |
57 | }; |
58 | ||
59 | int c; | |
60 | ||
61 | assert(argc >= 0); | |
62 | assert(argv); | |
63 | ||
0d8930fd | 64 | while ((c = getopt_long(argc, argv, "hp:M:", options, NULL)) >= 0) |
798c486f DM |
65 | |
66 | switch (c) { | |
67 | ||
68 | case 'h': | |
b6056ea3 | 69 | return help(); |
798c486f DM |
70 | |
71 | case ARG_VERSION: | |
72 | return version(); | |
73 | ||
cedfd142 | 74 | case ARG_USER: |
4870133b | 75 | arg_runtime_scope = RUNTIME_SCOPE_USER; |
cedfd142 LP |
76 | break; |
77 | ||
78 | case ARG_SYSTEM: | |
4870133b | 79 | arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; |
cedfd142 LP |
80 | break; |
81 | ||
798c486f DM |
82 | case 'p': |
83 | arg_bus_path = optarg; | |
84 | break; | |
85 | ||
19df1528 SL |
86 | case 'M': |
87 | arg_bus_path = optarg; | |
19df1528 | 88 | arg_transport = BUS_TRANSPORT_MACHINE; |
19df1528 | 89 | break; |
b6056ea3 LP |
90 | |
91 | case '?': | |
92 | return -EINVAL; | |
93 | ||
798c486f | 94 | default: |
baaa35ad ZJS |
95 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
96 | "Unknown option code %c", c); | |
798c486f | 97 | } |
798c486f DM |
98 | |
99 | return 1; | |
100 | } | |
101 | ||
1b425cb2 | 102 | static int run(int argc, char *argv[]) { |
92e31da1 | 103 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL, *b = NULL; |
798c486f DM |
104 | sd_id128_t server_id; |
105 | bool is_unix; | |
106 | int r, in_fd, out_fd; | |
107 | ||
108 | log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); | |
109 | log_parse_environment(); | |
110 | log_open(); | |
111 | ||
112 | r = parse_argv(argc, argv); | |
113 | if (r <= 0) | |
1b425cb2 | 114 | return r; |
798c486f DM |
115 | |
116 | r = sd_listen_fds(0); | |
117 | if (r == 0) { | |
118 | in_fd = STDIN_FILENO; | |
119 | out_fd = STDOUT_FILENO; | |
120 | } else if (r == 1) { | |
121 | in_fd = SD_LISTEN_FDS_START; | |
122 | out_fd = SD_LISTEN_FDS_START; | |
451e16e0 | 123 | } else |
a80f1784 | 124 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "More than one file descriptor was passed."); |
798c486f DM |
125 | |
126 | is_unix = | |
127 | sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && | |
128 | sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; | |
129 | ||
130 | r = sd_bus_new(&a); | |
1b425cb2 ZJS |
131 | if (r < 0) |
132 | return log_error_errno(r, "Failed to allocate bus: %m"); | |
798c486f | 133 | |
19df1528 | 134 | if (arg_transport == BUS_TRANSPORT_MACHINE) |
4870133b | 135 | r = bus_set_address_machine(a, arg_runtime_scope, arg_bus_path); |
19df1528 SL |
136 | else |
137 | r = sd_bus_set_address(a, arg_bus_path); | |
1b425cb2 ZJS |
138 | if (r < 0) |
139 | return log_error_errno(r, "Failed to set address to connect to: %m"); | |
798c486f DM |
140 | |
141 | r = sd_bus_negotiate_fds(a, is_unix); | |
1b425cb2 ZJS |
142 | if (r < 0) |
143 | return log_error_errno(r, "Failed to set FD negotiation: %m"); | |
798c486f DM |
144 | |
145 | r = sd_bus_start(a); | |
1b425cb2 ZJS |
146 | if (r < 0) |
147 | return log_error_errno(r, "Failed to start bus client: %m"); | |
798c486f DM |
148 | |
149 | r = sd_bus_get_bus_id(a, &server_id); | |
1b425cb2 ZJS |
150 | if (r < 0) |
151 | return log_error_errno(r, "Failed to get server ID: %m"); | |
798c486f DM |
152 | |
153 | r = sd_bus_new(&b); | |
1b425cb2 ZJS |
154 | if (r < 0) |
155 | return log_error_errno(r, "Failed to allocate bus: %m"); | |
798c486f DM |
156 | |
157 | r = sd_bus_set_fd(b, in_fd, out_fd); | |
1b425cb2 ZJS |
158 | if (r < 0) |
159 | return log_error_errno(r, "Failed to set fds: %m"); | |
798c486f DM |
160 | |
161 | r = sd_bus_set_server(b, 1, server_id); | |
1b425cb2 ZJS |
162 | if (r < 0) |
163 | return log_error_errno(r, "Failed to set server mode: %m"); | |
798c486f DM |
164 | |
165 | r = sd_bus_negotiate_fds(b, is_unix); | |
1b425cb2 ZJS |
166 | if (r < 0) |
167 | return log_error_errno(r, "Failed to set FD negotiation: %m"); | |
798c486f DM |
168 | |
169 | r = sd_bus_set_anonymous(b, true); | |
1b425cb2 ZJS |
170 | if (r < 0) |
171 | return log_error_errno(r, "Failed to set anonymous authentication: %m"); | |
798c486f DM |
172 | |
173 | r = sd_bus_start(b); | |
1b425cb2 ZJS |
174 | if (r < 0) |
175 | return log_error_errno(r, "Failed to start bus client: %m"); | |
798c486f DM |
176 | |
177 | for (;;) { | |
35bca925 | 178 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
798c486f | 179 | int events_a, events_b, fd; |
d9e2af0a YW |
180 | usec_t timeout_a, timeout_b, t; |
181 | ||
182 | assert_cc(sizeof(usec_t) == sizeof(uint64_t)); | |
798c486f DM |
183 | |
184 | r = sd_bus_process(a, &m); | |
0321248b LP |
185 | if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */ |
186 | break; | |
1b425cb2 ZJS |
187 | if (r < 0) |
188 | return log_error_errno(r, "Failed to process bus a: %m"); | |
798c486f | 189 | if (m) { |
0321248b LP |
190 | if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) |
191 | break; | |
192 | ||
798c486f | 193 | r = sd_bus_send(b, m, NULL); |
1b425cb2 ZJS |
194 | if (r < 0) |
195 | return log_error_errno(r, "Failed to send message: %m"); | |
798c486f DM |
196 | } |
197 | ||
198 | if (r > 0) | |
199 | continue; | |
200 | ||
201 | r = sd_bus_process(b, &m); | |
0321248b LP |
202 | if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */ |
203 | break; | |
bb44fd07 | 204 | if (r < 0) |
4e17e5c2 | 205 | return log_error_errno(r, "Failed to process bus: %m"); |
798c486f | 206 | if (m) { |
0321248b LP |
207 | if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) |
208 | break; | |
209 | ||
798c486f | 210 | r = sd_bus_send(a, m, NULL); |
1b425cb2 ZJS |
211 | if (r < 0) |
212 | return log_error_errno(r, "Failed to send message: %m"); | |
798c486f DM |
213 | } |
214 | ||
215 | if (r > 0) | |
216 | continue; | |
217 | ||
218 | fd = sd_bus_get_fd(a); | |
1b425cb2 ZJS |
219 | if (fd < 0) |
220 | return log_error_errno(fd, "Failed to get fd: %m"); | |
798c486f DM |
221 | |
222 | events_a = sd_bus_get_events(a); | |
1b425cb2 ZJS |
223 | if (events_a < 0) |
224 | return log_error_errno(events_a, "Failed to get events mask: %m"); | |
798c486f DM |
225 | |
226 | r = sd_bus_get_timeout(a, &timeout_a); | |
1b425cb2 ZJS |
227 | if (r < 0) |
228 | return log_error_errno(r, "Failed to get timeout: %m"); | |
798c486f DM |
229 | |
230 | events_b = sd_bus_get_events(b); | |
1b425cb2 ZJS |
231 | if (events_b < 0) |
232 | return log_error_errno(events_b, "Failed to get events mask: %m"); | |
798c486f DM |
233 | |
234 | r = sd_bus_get_timeout(b, &timeout_b); | |
1b425cb2 ZJS |
235 | if (r < 0) |
236 | return log_error_errno(r, "Failed to get timeout: %m"); | |
798c486f | 237 | |
d9e2af0a | 238 | t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC)); |
798c486f | 239 | |
dad28bff LP |
240 | struct pollfd p[3] = { |
241 | { .fd = fd, .events = events_a }, | |
242 | { .fd = STDIN_FILENO, .events = events_b & POLLIN }, | |
243 | { .fd = STDOUT_FILENO, .events = events_b & POLLOUT }, | |
244 | }; | |
245 | ||
d9e2af0a | 246 | r = ppoll_usec(p, ELEMENTSOF(p), t); |
bb44fd07 | 247 | if (r < 0 && !ERRNO_IS_TRANSIENT(r)) /* don't be bothered by signals, i.e. EINTR */ |
d9e2af0a | 248 | return log_error_errno(r, "ppoll() failed: %m"); |
798c486f DM |
249 | } |
250 | ||
1b425cb2 | 251 | return 0; |
798c486f | 252 | } |
1b425cb2 ZJS |
253 | |
254 | DEFINE_MAIN_FUNCTION(run); |