]>
Commit | Line | Data |
---|---|---|
798c486f DM |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2010 Lennart Poettering | |
5 | ||
6 | systemd is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU Lesser General Public License as published by | |
8 | the Free Software Foundation; either version 2.1 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | systemd is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public License | |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
18 | ***/ | |
19 | ||
20 | #include <errno.h> | |
21 | #include <getopt.h> | |
22 | #include <poll.h> | |
23 | #include <stddef.h> | |
24 | #include <string.h> | |
25 | #include <unistd.h> | |
26 | ||
27 | #include "sd-bus.h" | |
28 | #include "sd-daemon.h" | |
29 | ||
30 | #include "bus-internal.h" | |
31 | #include "bus-util.h" | |
32 | #include "build.h" | |
33 | #include "log.h" | |
34 | #include "util.h" | |
35 | ||
36 | #define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" | |
37 | ||
38 | const char *arg_bus_path = DEFAULT_BUS_PATH; | |
39 | ||
40 | static int help(void) { | |
41 | ||
42 | printf("%s [OPTIONS...]\n\n" | |
43 | "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n" | |
44 | " -h --help Show this help\n" | |
45 | " --version Show package version\n" | |
46 | " --bus-path=PATH Path to the kernel bus (default: %s)\n", | |
47 | program_invocation_short_name, DEFAULT_BUS_PATH); | |
48 | ||
49 | return 0; | |
50 | } | |
51 | ||
52 | static int parse_argv(int argc, char *argv[]) { | |
53 | ||
54 | enum { | |
55 | ARG_VERSION = 0x100, | |
56 | }; | |
57 | ||
58 | static const struct option options[] = { | |
59 | { "help", no_argument, NULL, 'h' }, | |
60 | { "bus-path", required_argument, NULL, 'p' }, | |
61 | { NULL, 0, NULL, 0 } | |
62 | }; | |
63 | ||
64 | int c; | |
65 | ||
66 | assert(argc >= 0); | |
67 | assert(argv); | |
68 | ||
69 | while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) { | |
70 | ||
71 | switch (c) { | |
72 | ||
73 | case 'h': | |
74 | help(); | |
75 | return 0; | |
76 | ||
77 | case ARG_VERSION: | |
78 | return version(); | |
79 | ||
80 | case '?': | |
81 | return -EINVAL; | |
82 | ||
83 | case 'p': | |
84 | arg_bus_path = optarg; | |
85 | break; | |
86 | ||
87 | default: | |
88 | log_error("Unknown option code %c", c); | |
89 | return -EINVAL; | |
90 | } | |
91 | } | |
92 | ||
93 | return 1; | |
94 | } | |
95 | ||
96 | int main(int argc, char *argv[]) { | |
97 | _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; | |
98 | sd_id128_t server_id; | |
99 | bool is_unix; | |
100 | int r, in_fd, out_fd; | |
101 | ||
102 | log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); | |
103 | log_parse_environment(); | |
104 | log_open(); | |
105 | ||
106 | r = parse_argv(argc, argv); | |
107 | if (r <= 0) | |
108 | goto finish; | |
109 | ||
110 | r = sd_listen_fds(0); | |
111 | if (r == 0) { | |
112 | in_fd = STDIN_FILENO; | |
113 | out_fd = STDOUT_FILENO; | |
114 | } else if (r == 1) { | |
115 | in_fd = SD_LISTEN_FDS_START; | |
116 | out_fd = SD_LISTEN_FDS_START; | |
117 | } else { | |
118 | log_error("Illegal number of file descriptors passed\n"); | |
119 | goto finish; | |
120 | } | |
121 | ||
122 | is_unix = | |
123 | sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && | |
124 | sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; | |
125 | ||
126 | r = sd_bus_new(&a); | |
127 | if (r < 0) { | |
128 | log_error_errno(r, "Failed to allocate bus: %m"); | |
129 | goto finish; | |
130 | } | |
131 | ||
132 | r = sd_bus_set_address(a, arg_bus_path); | |
133 | if (r < 0) { | |
134 | log_error_errno(r, "Failed to set address to connect to: %m"); | |
135 | goto finish; | |
136 | } | |
137 | ||
138 | r = sd_bus_negotiate_fds(a, is_unix); | |
139 | if (r < 0) { | |
140 | log_error_errno(r, "Failed to set FD negotiation: %m"); | |
141 | goto finish; | |
142 | } | |
143 | ||
144 | r = sd_bus_start(a); | |
145 | if (r < 0) { | |
146 | log_error_errno(r, "Failed to start bus client: %m"); | |
147 | goto finish; | |
148 | } | |
149 | ||
150 | r = sd_bus_get_bus_id(a, &server_id); | |
151 | if (r < 0) { | |
152 | log_error_errno(r, "Failed to get server ID: %m"); | |
153 | goto finish; | |
154 | } | |
155 | ||
156 | r = sd_bus_new(&b); | |
157 | if (r < 0) { | |
158 | log_error_errno(r, "Failed to allocate bus: %m"); | |
159 | goto finish; | |
160 | } | |
161 | ||
162 | r = sd_bus_set_fd(b, in_fd, out_fd); | |
163 | if (r < 0) { | |
164 | log_error_errno(r, "Failed to set fds: %m"); | |
165 | goto finish; | |
166 | } | |
167 | ||
168 | r = sd_bus_set_server(b, 1, server_id); | |
169 | if (r < 0) { | |
170 | log_error_errno(r, "Failed to set server mode: %m"); | |
171 | goto finish; | |
172 | } | |
173 | ||
174 | r = sd_bus_negotiate_fds(b, is_unix); | |
175 | if (r < 0) { | |
176 | log_error_errno(r, "Failed to set FD negotiation: %m"); | |
177 | goto finish; | |
178 | } | |
179 | ||
180 | r = sd_bus_set_anonymous(b, true); | |
181 | if (r < 0) { | |
182 | log_error_errno(r, "Failed to set anonymous authentication: %m"); | |
183 | goto finish; | |
184 | } | |
185 | ||
186 | r = sd_bus_start(b); | |
187 | if (r < 0) { | |
188 | log_error_errno(r, "Failed to start bus client: %m"); | |
189 | goto finish; | |
190 | } | |
191 | ||
192 | for (;;) { | |
7f508f2c | 193 | _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; |
798c486f DM |
194 | int events_a, events_b, fd; |
195 | uint64_t timeout_a, timeout_b, t; | |
196 | struct timespec _ts, *ts; | |
197 | ||
198 | r = sd_bus_process(a, &m); | |
199 | if (r < 0) { | |
200 | log_error_errno(r, "Failed to process bus a: %m"); | |
201 | goto finish; | |
202 | } | |
203 | ||
204 | if (m) { | |
205 | r = sd_bus_send(b, m, NULL); | |
206 | if (r < 0) { | |
207 | log_error_errno(r, "Failed to send message: %m"); | |
208 | goto finish; | |
209 | } | |
210 | } | |
211 | ||
212 | if (r > 0) | |
213 | continue; | |
214 | ||
215 | r = sd_bus_process(b, &m); | |
216 | if (r < 0) { | |
217 | /* treat 'connection reset by peer' as clean exit condition */ | |
218 | if (r == -ECONNRESET) | |
219 | r = 0; | |
220 | ||
221 | goto finish; | |
222 | } | |
223 | ||
224 | if (m) { | |
225 | r = sd_bus_send(a, m, NULL); | |
226 | if (r < 0) { | |
227 | log_error_errno(r, "Failed to send message: %m"); | |
228 | goto finish; | |
229 | } | |
230 | } | |
231 | ||
232 | if (r > 0) | |
233 | continue; | |
234 | ||
235 | fd = sd_bus_get_fd(a); | |
236 | if (fd < 0) { | |
20268e0c | 237 | r = fd; |
798c486f DM |
238 | log_error_errno(r, "Failed to get fd: %m"); |
239 | goto finish; | |
240 | } | |
241 | ||
242 | events_a = sd_bus_get_events(a); | |
243 | if (events_a < 0) { | |
20268e0c | 244 | r = events_a; |
798c486f DM |
245 | log_error_errno(r, "Failed to get events mask: %m"); |
246 | goto finish; | |
247 | } | |
248 | ||
249 | r = sd_bus_get_timeout(a, &timeout_a); | |
250 | if (r < 0) { | |
251 | log_error_errno(r, "Failed to get timeout: %m"); | |
252 | goto finish; | |
253 | } | |
254 | ||
255 | events_b = sd_bus_get_events(b); | |
256 | if (events_b < 0) { | |
20268e0c | 257 | r = events_b; |
798c486f DM |
258 | log_error_errno(r, "Failed to get events mask: %m"); |
259 | goto finish; | |
260 | } | |
261 | ||
262 | r = sd_bus_get_timeout(b, &timeout_b); | |
263 | if (r < 0) { | |
264 | log_error_errno(r, "Failed to get timeout: %m"); | |
265 | goto finish; | |
266 | } | |
267 | ||
268 | t = timeout_a; | |
269 | if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) | |
270 | t = timeout_b; | |
271 | ||
272 | if (t == (uint64_t) -1) | |
273 | ts = NULL; | |
274 | else { | |
275 | usec_t nw; | |
276 | ||
277 | nw = now(CLOCK_MONOTONIC); | |
278 | if (t > nw) | |
279 | t -= nw; | |
280 | else | |
281 | t = 0; | |
282 | ||
283 | ts = timespec_store(&_ts, t); | |
284 | } | |
285 | ||
286 | { | |
287 | struct pollfd p[3] = { | |
288 | {.fd = fd, .events = events_a, }, | |
289 | {.fd = STDIN_FILENO, .events = events_b & POLLIN, }, | |
290 | {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }}; | |
291 | ||
292 | r = ppoll(p, ELEMENTSOF(p), ts, NULL); | |
293 | } | |
294 | if (r < 0) { | |
295 | log_error("ppoll() failed: %m"); | |
296 | goto finish; | |
297 | } | |
298 | } | |
299 | ||
798c486f DM |
300 | finish: |
301 | return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; | |
302 | } |