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