chiark / gitweb /
ab1a43ab1a99f586ccf57499810106e5c2c1d9a6
[elogind.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_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_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                 int events_a, events_b, fd;
128                 uint64_t timeout_a, timeout_b, t;
129                 struct timespec _ts, *ts;
130
131                 r = sd_bus_process(a, &m);
132                 if (r < 0) {
133                         log_error("Failed to process bus: %s", strerror(-r));
134                         goto finish;
135                 }
136
137                 if (m) {
138                         r = sd_bus_send(b, m, NULL);
139                         if (r < 0) {
140                                 log_error("Failed to send message: %s", strerror(-r));
141                                 goto finish;
142                         }
143                 }
144
145                 if (r > 0)
146                         continue;
147
148                 r = sd_bus_process(b, &m);
149                 if (r < 0) {
150                         log_error("Failed to process bus: %s", strerror(-r));
151                         goto finish;
152                 }
153
154                 if (m) {
155                         r = sd_bus_send(a, m, NULL);
156                         if (r < 0) {
157                                 log_error("Failed to send message: %s", strerror(-r));
158                                 goto finish;
159                         }
160                 }
161
162                 if (r > 0)
163                         continue;
164
165                 fd = sd_bus_get_fd(a);
166                 if (fd < 0) {
167                         log_error("Failed to get fd: %s", strerror(-r));
168                         goto finish;
169                 }
170
171                 events_a = sd_bus_get_events(a);
172                 if (events_a < 0) {
173                         log_error("Failed to get events mask: %s", strerror(-r));
174                         goto finish;
175                 }
176
177                 r = sd_bus_get_timeout(a, &timeout_a);
178                 if (r < 0) {
179                         log_error("Failed to get timeout: %s", strerror(-r));
180                         goto finish;
181                 }
182
183                 events_b = sd_bus_get_events(b);
184                 if (events_b < 0) {
185                         log_error("Failed to get events mask: %s", strerror(-r));
186                         goto finish;
187                 }
188
189                 r = sd_bus_get_timeout(b, &timeout_b);
190                 if (r < 0) {
191                         log_error("Failed to get timeout: %s", strerror(-r));
192                         goto finish;
193                 }
194
195                 t = timeout_a;
196                 if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
197                         t = timeout_b;
198
199                 if (t == (uint64_t) -1)
200                         ts = NULL;
201                 else {
202                         usec_t nw;
203
204                         nw = now(CLOCK_MONOTONIC);
205                         if (t > nw)
206                                 t -= nw;
207                         else
208                                 t = 0;
209
210                         ts = timespec_store(&_ts, t);
211                 }
212
213                 {
214                         struct pollfd p[3] = {
215                                 {.fd = fd,            .events = events_a, },
216                                 {.fd = STDIN_FILENO,  .events = events_b & POLLIN, },
217                                 {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
218
219                         r = ppoll(p, ELEMENTSOF(p), ts, NULL);
220                 }
221                 if (r < 0) {
222                         log_error("ppoll() failed: %m");
223                         goto finish;
224                 }
225         }
226
227         r = 0;
228
229 finish:
230         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
231 }