chiark / gitweb /
07218e90c5d2322666dbc621ec7b790c265027ff
[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 #include "bus-util.h"
40
41 int main(int argc, char *argv[]) {
42         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
43         sd_id128_t server_id;
44         bool is_unix;
45         int r;
46
47         if (argc > 1) {
48                 log_error("This program takes no argument.");
49                 return EXIT_FAILURE;
50         }
51
52         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
53         log_parse_environment();
54         log_open();
55
56         is_unix =
57                 sd_is_socket(STDIN_FILENO, AF_UNIX, 0, 0) > 0 &&
58                 sd_is_socket(STDOUT_FILENO, AF_UNIX, 0, 0) > 0;
59
60         r = sd_bus_new(&a);
61         if (r < 0) {
62                 log_error("Failed to allocate bus: %s", strerror(-r));
63                 goto finish;
64         }
65
66         r = sd_bus_set_address(a, "unix:path=/run/dbus/system_bus_socket");
67         if (r < 0) {
68                 log_error("Failed to set address to connect to: %s", strerror(-r));
69                 goto finish;
70         }
71
72         r = sd_bus_negotiate_fds(a, is_unix);
73         if (r < 0) {
74                 log_error("Failed to set FD negotiation: %s", strerror(-r));
75                 goto finish;
76         }
77
78         r = sd_bus_start(a);
79         if (r < 0) {
80                 log_error("Failed to start bus client: %s", strerror(-r));
81                 goto finish;
82         }
83
84         r = sd_bus_get_server_id(a, &server_id);
85         if (r < 0) {
86                 log_error("Failed to get server ID: %s", strerror(-r));
87                 goto finish;
88         }
89
90         r = sd_bus_new(&b);
91         if (r < 0) {
92                 log_error("Failed to allocate bus: %s", strerror(-r));
93                 goto finish;
94         }
95
96         r = sd_bus_set_fd(b, STDIN_FILENO, STDOUT_FILENO);
97         if (r < 0) {
98                 log_error("Failed to set fds: %s", strerror(-r));
99                 goto finish;
100         }
101
102         r = sd_bus_set_server(b, 1, server_id);
103         if (r < 0) {
104                 log_error("Failed to set server mode: %s", strerror(-r));
105                 goto finish;
106         }
107
108         r = sd_bus_negotiate_fds(b, is_unix);
109         if (r < 0) {
110                 log_error("Failed to set FD negotiation: %s", strerror(-r));
111                 goto finish;
112         }
113
114         r = sd_bus_set_anonymous(b, true);
115         if (r < 0) {
116                 log_error("Failed to set anonymous authentication: %s", strerror(-r));
117                 goto finish;
118         }
119
120         r = sd_bus_start(b);
121         if (r < 0) {
122                 log_error("Failed to start bus client: %s", strerror(-r));
123                 goto finish;
124         }
125
126         for (;;) {
127                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
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                 {
215                         struct pollfd p[3] = {
216                                 {.fd = fd,            .events = events_a, },
217                                 {.fd = STDIN_FILENO,  .events = events_b & POLLIN, },
218                                 {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
219
220                         r = ppoll(p, ELEMENTSOF(p), ts, NULL);
221                 }
222                 if (r < 0) {
223                         log_error("ppoll() failed: %m");
224                         goto finish;
225                 }
226         }
227
228         r = 0;
229
230 finish:
231         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
232 }