]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-server.c
tmpfiles: accurately report creation results
[thirdparty/systemd.git] / src / libsystemd / sd-bus / test-bus-server.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 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 <assert.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include "log.h"
29 #include "util.h"
30 #include "macro.h"
31
32 #include "sd-bus.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36
37 struct context {
38 int fds[2];
39
40 bool client_negotiate_unix_fds;
41 bool server_negotiate_unix_fds;
42
43 bool client_anonymous_auth;
44 bool server_anonymous_auth;
45 };
46
47 static void *server(void *p) {
48 struct context *c = p;
49 sd_bus *bus = NULL;
50 sd_id128_t id;
51 bool quit = false;
52 int r;
53
54 assert_se(sd_id128_randomize(&id) >= 0);
55
56 assert_se(sd_bus_new(&bus) >= 0);
57 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
58 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
59 assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0);
60 assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0);
61 assert_se(sd_bus_start(bus) >= 0);
62
63 while (!quit) {
64 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
65
66 r = sd_bus_process(bus, &m);
67 if (r < 0) {
68 log_error_errno(r, "Failed to process requests: %m");
69 goto fail;
70 }
71
72 if (r == 0) {
73 r = sd_bus_wait(bus, (uint64_t) -1);
74 if (r < 0) {
75 log_error_errno(r, "Failed to wait: %m");
76 goto fail;
77 }
78
79 continue;
80 }
81
82 if (!m)
83 continue;
84
85 log_info("Got message! member=%s", strna(sd_bus_message_get_member(m)));
86
87 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) {
88
89 assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds));
90
91 r = sd_bus_message_new_method_return(m, &reply);
92 if (r < 0) {
93 log_error_errno(r, "Failed to allocate return: %m");
94 goto fail;
95 }
96
97 quit = true;
98
99 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
100 r = sd_bus_message_new_method_error(
101 m,
102 &reply,
103 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
104 if (r < 0) {
105 log_error_errno(r, "Failed to allocate return: %m");
106 goto fail;
107 }
108 }
109
110 if (reply) {
111 r = sd_bus_send(bus, reply, NULL);
112 if (r < 0) {
113 log_error_errno(r, "Failed to send reply: %m");
114 goto fail;
115 }
116 }
117 }
118
119 r = 0;
120
121 fail:
122 if (bus) {
123 sd_bus_flush(bus);
124 sd_bus_unref(bus);
125 }
126
127 return INT_TO_PTR(r);
128 }
129
130 static int client(struct context *c) {
131 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
132 _cleanup_bus_unref_ sd_bus *bus = NULL;
133 sd_bus_error error = SD_BUS_ERROR_NULL;
134 int r;
135
136 assert_se(sd_bus_new(&bus) >= 0);
137 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
138 assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0);
139 assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0);
140 assert_se(sd_bus_start(bus) >= 0);
141
142 r = sd_bus_message_new_method_call(
143 bus,
144 &m,
145 "org.freedesktop.systemd.test",
146 "/",
147 "org.freedesktop.systemd.test",
148 "Exit");
149 if (r < 0)
150 return log_error_errno(r, "Failed to allocate method call: %m");
151
152 r = sd_bus_call(bus, m, 0, &error, &reply);
153 if (r < 0) {
154 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
155 return r;
156 }
157
158 return 0;
159 }
160
161 static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds,
162 bool client_anonymous_auth, bool server_anonymous_auth) {
163
164 struct context c;
165 pthread_t s;
166 void *p;
167 int r, q;
168
169 zero(c);
170
171 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
172
173 c.client_negotiate_unix_fds = client_negotiate_unix_fds;
174 c.server_negotiate_unix_fds = server_negotiate_unix_fds;
175 c.client_anonymous_auth = client_anonymous_auth;
176 c.server_anonymous_auth = server_anonymous_auth;
177
178 r = pthread_create(&s, NULL, server, &c);
179 if (r != 0)
180 return -r;
181
182 r = client(&c);
183
184 q = pthread_join(s, &p);
185 if (q != 0)
186 return -q;
187
188 if (r < 0)
189 return r;
190
191 if (PTR_TO_INT(p) < 0)
192 return PTR_TO_INT(p);
193
194 return 0;
195 }
196
197 int main(int argc, char *argv[]) {
198 int r;
199
200 r = test_one(true, true, false, false);
201 assert_se(r >= 0);
202
203 r = test_one(true, false, false, false);
204 assert_se(r >= 0);
205
206 r = test_one(false, true, false, false);
207 assert_se(r >= 0);
208
209 r = test_one(false, false, false, false);
210 assert_se(r >= 0);
211
212 r = test_one(true, true, true, true);
213 assert_se(r >= 0);
214
215 r = test_one(true, true, false, true);
216 assert_se(r >= 0);
217
218 r = test_one(true, true, true, false);
219 assert_se(r == -EPERM);
220
221 return EXIT_SUCCESS;
222 }