]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/stdio-bridge/stdio-bridge.c
stdio-bridge: rework stdio bridge to use libsystemd-bus
[thirdparty/systemd.git] / src / stdio-bridge / stdio-bridge.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/poll.h>
30 #include <stddef.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "socket-util.h"
35 #include "sd-daemon.h"
36 #include "sd-bus.h"
37 #include "bus-internal.h"
38 #include "bus-message.h"
39
40 int main(int argc, char *argv[]) {
41 _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
42 sd_id128_t server_id;
43 bool is_unix;
44 int r;
45
46 if (argc > 1) {
47 log_error("This program takes no argument.");
48 return EXIT_FAILURE;
49 }
50
51 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
52 log_parse_environment();
53 log_open();
54
55 is_unix =
56 sd_is_socket(STDIN_FILENO, AF_UNIX, 0, 0) > 0 &&
57 sd_is_socket(STDOUT_FILENO, AF_UNIX, 0, 0) > 0;
58
59 r = sd_bus_new(&a);
60 if (r < 0) {
61 log_error("Failed to allocate bus: %s", strerror(-r));
62 goto finish;
63 }
64
65 r = sd_bus_set_address(a, "unix:path=/run/dbus/system_bus_socket");
66 if (r < 0) {
67 log_error("Failed to set address to connect to: %s", strerror(-r));
68 goto finish;
69 }
70
71 r = sd_bus_set_negotiate_fds(a, is_unix);
72 if (r < 0) {
73 log_error("Failed to set FD negotiation: %s", strerror(-r));
74 goto finish;
75 }
76
77 r = sd_bus_start(a);
78 if (r < 0) {
79 log_error("Failed to start bus client: %s", strerror(-r));
80 goto finish;
81 }
82
83 r = sd_bus_get_server_id(a, &server_id);
84 if (r < 0) {
85 log_error("Failed to get server ID: %s", strerror(-r));
86 goto finish;
87 }
88
89 r = sd_bus_new(&b);
90 if (r < 0) {
91 log_error("Failed to allocate bus: %s", strerror(-r));
92 goto finish;
93 }
94
95 r = sd_bus_set_fd(b, STDIN_FILENO, STDOUT_FILENO);
96 if (r < 0) {
97 log_error("Failed to set fds: %s", strerror(-r));
98 goto finish;
99 }
100
101 r = sd_bus_set_server(b, 1, server_id);
102 if (r < 0) {
103 log_error("Failed to set server mode: %s", strerror(-r));
104 goto finish;
105 }
106
107 r = sd_bus_set_negotiate_fds(b, is_unix);
108 if (r < 0) {
109 log_error("Failed to set FD negotiation: %s", strerror(-r));
110 goto finish;
111 }
112
113 r = sd_bus_set_anonymous(b, true);
114 if (r < 0) {
115 log_error("Failed to set anonymous authentication: %s", strerror(-r));
116 goto finish;
117 }
118
119 r = sd_bus_start(b);
120 if (r < 0) {
121 log_error("Failed to start bus client: %s", strerror(-r));
122 goto finish;
123 }
124
125 for (;;) {
126 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
127 struct pollfd p[3];
128 int events_a, events_b, fd;
129 uint64_t timeout_a, timeout_b, t;
130 struct timespec _ts, *ts;
131
132 r = sd_bus_process(a, &m);
133 if (r < 0) {
134 log_error("Failed to process bus: %s", strerror(-r));
135 goto finish;
136 }
137
138 if (m) {
139 r = sd_bus_send(b, m, NULL);
140 if (r < 0) {
141 log_error("Failed to send message: %s", strerror(-r));
142 goto finish;
143 }
144 }
145
146 if (r > 0)
147 continue;
148
149 r = sd_bus_process(b, &m);
150 if (r < 0) {
151 log_error("Failed to process bus: %s", strerror(-r));
152 goto finish;
153 }
154
155 if (m) {
156 r = sd_bus_send(a, m, NULL);
157 if (r < 0) {
158 log_error("Failed to send message: %s", strerror(-r));
159 goto finish;
160 }
161 }
162
163 if (r > 0)
164 continue;
165
166 fd = sd_bus_get_fd(a);
167 if (fd < 0) {
168 log_error("Failed to get fd: %s", strerror(-r));
169 goto finish;
170 }
171
172 events_a = sd_bus_get_events(a);
173 if (events_a < 0) {
174 log_error("Failed to get events mask: %s", strerror(-r));
175 goto finish;
176 }
177
178 r = sd_bus_get_timeout(a, &timeout_a);
179 if (r < 0) {
180 log_error("Failed to get timeout: %s", strerror(-r));
181 goto finish;
182 }
183
184 events_b = sd_bus_get_events(b);
185 if (events_b < 0) {
186 log_error("Failed to get events mask: %s", strerror(-r));
187 goto finish;
188 }
189
190 r = sd_bus_get_timeout(b, &timeout_b);
191 if (r < 0) {
192 log_error("Failed to get timeout: %s", strerror(-r));
193 goto finish;
194 }
195
196 t = timeout_a;
197 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
198 t = timeout_b;
199
200 if (t == (uint64_t) -1)
201 ts = NULL;
202 else {
203 usec_t nw;
204
205 nw = now(CLOCK_MONOTONIC);
206 if (t > nw)
207 t -= nw;
208 else
209 t = 0;
210
211 ts = timespec_store(&_ts, t);
212 }
213
214 zero(p);
215 p[0].fd = fd;
216 p[0].events = events_a;
217 p[1].fd = STDIN_FILENO;
218 p[1].events = events_b & POLLIN;
219 p[2].fd = STDOUT_FILENO;
220 p[2].events = events_b & POLLOUT;
221
222 r = ppoll(p, ELEMENTSOF(p), ts, NULL);
223 if (r < 0) {
224 log_error("ppoll() failed: %m");
225 goto finish;
226 }
227 }
228
229 r = 0;
230
231 finish:
232 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
233 }