]>
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 | ||
aa976d87 | 108 | log_setup(); |
798c486f DM |
109 | |
110 | r = parse_argv(argc, argv); | |
111 | if (r <= 0) | |
1b425cb2 | 112 | return r; |
798c486f DM |
113 | |
114 | r = sd_listen_fds(0); | |
115 | if (r == 0) { | |
116 | in_fd = STDIN_FILENO; | |
117 | out_fd = STDOUT_FILENO; | |
118 | } else if (r == 1) { | |
119 | in_fd = SD_LISTEN_FDS_START; | |
120 | out_fd = SD_LISTEN_FDS_START; | |
451e16e0 | 121 | } else |
a80f1784 | 122 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "More than one file descriptor was passed."); |
798c486f DM |
123 | |
124 | is_unix = | |
125 | sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && | |
126 | sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; | |
127 | ||
128 | r = sd_bus_new(&a); | |
1b425cb2 ZJS |
129 | if (r < 0) |
130 | return log_error_errno(r, "Failed to allocate bus: %m"); | |
798c486f | 131 | |
19df1528 | 132 | if (arg_transport == BUS_TRANSPORT_MACHINE) |
4870133b | 133 | r = bus_set_address_machine(a, arg_runtime_scope, arg_bus_path); |
19df1528 SL |
134 | else |
135 | r = sd_bus_set_address(a, arg_bus_path); | |
1b425cb2 ZJS |
136 | if (r < 0) |
137 | return log_error_errno(r, "Failed to set address to connect to: %m"); | |
798c486f DM |
138 | |
139 | r = sd_bus_negotiate_fds(a, is_unix); | |
1b425cb2 ZJS |
140 | if (r < 0) |
141 | return log_error_errno(r, "Failed to set FD negotiation: %m"); | |
798c486f DM |
142 | |
143 | r = sd_bus_start(a); | |
1b425cb2 ZJS |
144 | if (r < 0) |
145 | return log_error_errno(r, "Failed to start bus client: %m"); | |
798c486f DM |
146 | |
147 | r = sd_bus_get_bus_id(a, &server_id); | |
1b425cb2 ZJS |
148 | if (r < 0) |
149 | return log_error_errno(r, "Failed to get server ID: %m"); | |
798c486f DM |
150 | |
151 | r = sd_bus_new(&b); | |
1b425cb2 ZJS |
152 | if (r < 0) |
153 | return log_error_errno(r, "Failed to allocate bus: %m"); | |
798c486f DM |
154 | |
155 | r = sd_bus_set_fd(b, in_fd, out_fd); | |
1b425cb2 ZJS |
156 | if (r < 0) |
157 | return log_error_errno(r, "Failed to set fds: %m"); | |
798c486f DM |
158 | |
159 | r = sd_bus_set_server(b, 1, server_id); | |
1b425cb2 ZJS |
160 | if (r < 0) |
161 | return log_error_errno(r, "Failed to set server mode: %m"); | |
798c486f DM |
162 | |
163 | r = sd_bus_negotiate_fds(b, is_unix); | |
1b425cb2 ZJS |
164 | if (r < 0) |
165 | return log_error_errno(r, "Failed to set FD negotiation: %m"); | |
798c486f DM |
166 | |
167 | r = sd_bus_set_anonymous(b, true); | |
1b425cb2 ZJS |
168 | if (r < 0) |
169 | return log_error_errno(r, "Failed to set anonymous authentication: %m"); | |
798c486f DM |
170 | |
171 | r = sd_bus_start(b); | |
1b425cb2 ZJS |
172 | if (r < 0) |
173 | return log_error_errno(r, "Failed to start bus client: %m"); | |
798c486f DM |
174 | |
175 | for (;;) { | |
35bca925 | 176 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
798c486f | 177 | int events_a, events_b, fd; |
d9e2af0a YW |
178 | usec_t timeout_a, timeout_b, t; |
179 | ||
180 | assert_cc(sizeof(usec_t) == sizeof(uint64_t)); | |
798c486f DM |
181 | |
182 | r = sd_bus_process(a, &m); | |
0321248b | 183 | if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */ |
ccd31de8 | 184 | return 0; |
1b425cb2 ZJS |
185 | if (r < 0) |
186 | return log_error_errno(r, "Failed to process bus a: %m"); | |
798c486f | 187 | if (m) { |
0321248b | 188 | if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) |
ccd31de8 | 189 | return 0; |
0321248b | 190 | |
798c486f | 191 | r = sd_bus_send(b, m, NULL); |
1b425cb2 ZJS |
192 | if (r < 0) |
193 | return log_error_errno(r, "Failed to send message: %m"); | |
798c486f DM |
194 | } |
195 | ||
196 | if (r > 0) | |
197 | continue; | |
198 | ||
199 | r = sd_bus_process(b, &m); | |
0321248b | 200 | if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */ |
ccd31de8 | 201 | return 0; |
bb44fd07 | 202 | if (r < 0) |
4e17e5c2 | 203 | return log_error_errno(r, "Failed to process bus: %m"); |
798c486f | 204 | if (m) { |
0321248b | 205 | if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) |
ccd31de8 | 206 | return 0; |
0321248b | 207 | |
798c486f | 208 | r = sd_bus_send(a, m, NULL); |
1b425cb2 ZJS |
209 | if (r < 0) |
210 | return log_error_errno(r, "Failed to send message: %m"); | |
798c486f DM |
211 | } |
212 | ||
213 | if (r > 0) | |
214 | continue; | |
215 | ||
216 | fd = sd_bus_get_fd(a); | |
1b425cb2 ZJS |
217 | if (fd < 0) |
218 | return log_error_errno(fd, "Failed to get fd: %m"); | |
798c486f DM |
219 | |
220 | events_a = sd_bus_get_events(a); | |
1b425cb2 ZJS |
221 | if (events_a < 0) |
222 | return log_error_errno(events_a, "Failed to get events mask: %m"); | |
798c486f DM |
223 | |
224 | r = sd_bus_get_timeout(a, &timeout_a); | |
1b425cb2 ZJS |
225 | if (r < 0) |
226 | return log_error_errno(r, "Failed to get timeout: %m"); | |
798c486f DM |
227 | |
228 | events_b = sd_bus_get_events(b); | |
1b425cb2 ZJS |
229 | if (events_b < 0) |
230 | return log_error_errno(events_b, "Failed to get events mask: %m"); | |
798c486f DM |
231 | |
232 | r = sd_bus_get_timeout(b, &timeout_b); | |
1b425cb2 ZJS |
233 | if (r < 0) |
234 | return log_error_errno(r, "Failed to get timeout: %m"); | |
798c486f | 235 | |
d9e2af0a | 236 | t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC)); |
798c486f | 237 | |
dad28bff LP |
238 | struct pollfd p[3] = { |
239 | { .fd = fd, .events = events_a }, | |
240 | { .fd = STDIN_FILENO, .events = events_b & POLLIN }, | |
241 | { .fd = STDOUT_FILENO, .events = events_b & POLLOUT }, | |
242 | }; | |
243 | ||
d9e2af0a | 244 | r = ppoll_usec(p, ELEMENTSOF(p), t); |
bb44fd07 | 245 | if (r < 0 && !ERRNO_IS_TRANSIENT(r)) /* don't be bothered by signals, i.e. EINTR */ |
d9e2af0a | 246 | return log_error_errno(r, "ppoll() failed: %m"); |
798c486f | 247 | } |
798c486f | 248 | } |
1b425cb2 ZJS |
249 | |
250 | DEFINE_MAIN_FUNCTION(run); |