]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-objects.c
tmpfiles: accurately report creation results
[thirdparty/systemd.git] / src / libsystemd / sd-bus / test-bus-objects.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 #include "strv.h"
32
33 #include "sd-bus.h"
34 #include "bus-internal.h"
35 #include "bus-message.h"
36 #include "bus-util.h"
37 #include "bus-dump.h"
38
39 struct context {
40 int fds[2];
41 bool quit;
42 char *something;
43 char *automatic_string_property;
44 uint32_t automatic_integer_property;
45 };
46
47 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
48 struct context *c = userdata;
49 const char *s;
50 char *n = NULL;
51 int r;
52
53 r = sd_bus_message_read(m, "s", &s);
54 assert_se(r > 0);
55
56 n = strjoin("<<<", s, ">>>", NULL);
57 assert_se(n);
58
59 free(c->something);
60 c->something = n;
61
62 log_info("AlterSomething() called, got %s, returning %s", s, n);
63
64 /* This should fail, since the return type doesn't match */
65 assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
66
67 r = sd_bus_reply_method_return(m, "s", n);
68 assert_se(r >= 0);
69
70 return 1;
71 }
72
73 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
74 struct context *c = userdata;
75 int r;
76
77 c->quit = true;
78
79 log_info("Exit called");
80
81 r = sd_bus_reply_method_return(m, "");
82 assert_se(r >= 0);
83
84 return 1;
85 }
86
87 static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
88 struct context *c = userdata;
89 int r;
90
91 log_info("property get for %s called, returning \"%s\".", property, c->something);
92
93 r = sd_bus_message_append(reply, "s", c->something);
94 assert_se(r >= 0);
95
96 return 1;
97 }
98
99 static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
100 struct context *c = userdata;
101 const char *s;
102 char *n;
103 int r;
104
105 log_info("property set for %s called", property);
106
107 r = sd_bus_message_read(value, "s", &s);
108 assert_se(r >= 0);
109
110 n = strdup(s);
111 assert_se(n);
112
113 free(c->something);
114 c->something = n;
115
116 return 1;
117 }
118
119 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
120 _cleanup_free_ char *s = NULL;
121 const char *x;
122 int r;
123
124 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
125 r = sd_bus_message_append(reply, "s", s);
126 assert_se(r >= 0);
127
128 assert_se(x = startswith(path, "/value/"));
129
130 assert_se(PTR_TO_UINT(userdata) == 30);
131
132 return 1;
133 }
134
135 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
136 int r;
137
138 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
139
140 r = sd_bus_reply_method_return(m, NULL);
141 assert_se(r >= 0);
142
143 return 1;
144 }
145
146 static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
147 int r;
148
149 assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
150
151 r = sd_bus_reply_method_return(m, NULL);
152 assert_se(r >= 0);
153
154 return 1;
155 }
156
157 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
158 int r;
159
160 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
161
162 r = sd_bus_reply_method_return(m, NULL);
163 assert_se(r >= 0);
164
165 return 1;
166 }
167
168 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
169 int r;
170
171 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
172
173 r = sd_bus_reply_method_return(m, NULL);
174 assert_se(r >= 0);
175
176 return 1;
177 }
178
179 static int emit_object_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
180 int r;
181
182 assert_se(sd_bus_emit_object_added(bus, m->path) >= 0);
183
184 r = sd_bus_reply_method_return(m, NULL);
185 assert_se(r >= 0);
186
187 return 1;
188 }
189
190 static int emit_object_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
191 int r;
192
193 assert_se(sd_bus_emit_object_removed(bus, m->path) >= 0);
194
195 r = sd_bus_reply_method_return(m, NULL);
196 assert_se(r >= 0);
197
198 return 1;
199 }
200
201 static const sd_bus_vtable vtable[] = {
202 SD_BUS_VTABLE_START(0),
203 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
204 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
205 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
206 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
207 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
208 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
209 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
210 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
211 SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
212 SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
213 SD_BUS_VTABLE_END
214 };
215
216 static const sd_bus_vtable vtable2[] = {
217 SD_BUS_VTABLE_START(0),
218 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
219 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
220 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
221 SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
222 SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
223 SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
224 SD_BUS_VTABLE_END
225 };
226
227 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
228
229 if (object_path_startswith("/value", path))
230 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
231
232 return 1;
233 }
234
235 static void *server(void *p) {
236 struct context *c = p;
237 sd_bus *bus = NULL;
238 sd_id128_t id;
239 int r;
240
241 c->quit = false;
242
243 assert_se(sd_id128_randomize(&id) >= 0);
244
245 assert_se(sd_bus_new(&bus) >= 0);
246 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
247 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
248
249 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
250 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
251 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
252 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
253 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
254
255 assert_se(sd_bus_start(bus) >= 0);
256
257 log_error("Entering event loop on server");
258
259 while (!c->quit) {
260 log_error("Loop!");
261
262 r = sd_bus_process(bus, NULL);
263 if (r < 0) {
264 log_error_errno(r, "Failed to process requests: %m");
265 goto fail;
266 }
267
268 if (r == 0) {
269 r = sd_bus_wait(bus, (uint64_t) -1);
270 if (r < 0) {
271 log_error_errno(r, "Failed to wait: %m");
272 goto fail;
273 }
274
275 continue;
276 }
277 }
278
279 r = 0;
280
281 fail:
282 if (bus) {
283 sd_bus_flush(bus);
284 sd_bus_unref(bus);
285 }
286
287 return INT_TO_PTR(r);
288 }
289
290 static int client(struct context *c) {
291 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
292 _cleanup_bus_unref_ sd_bus *bus = NULL;
293 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
294 const char *s;
295 int r;
296
297 assert_se(sd_bus_new(&bus) >= 0);
298 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
299 assert_se(sd_bus_start(bus) >= 0);
300
301 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
302 assert_se(r >= 0);
303
304 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
305 assert_se(r >= 0);
306
307 r = sd_bus_message_read(reply, "s", &s);
308 assert_se(r >= 0);
309 assert_se(streq(s, "<<<hallo>>>"));
310
311 sd_bus_message_unref(reply);
312 reply = NULL;
313
314 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
315 assert_se(r < 0);
316 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
317
318 sd_bus_error_free(&error);
319
320 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
321 assert_se(r < 0);
322 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
323
324 sd_bus_error_free(&error);
325
326 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
327 assert_se(r >= 0);
328
329 r = sd_bus_message_read(reply, "s", &s);
330 assert_se(r >= 0);
331 assert_se(streq(s, "<<<hallo>>>"));
332
333 sd_bus_message_unref(reply);
334 reply = NULL;
335
336 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
337 assert_se(r >= 0);
338
339 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
340 assert_se(r >= 0);
341
342 r = sd_bus_message_read(reply, "s", &s);
343 assert_se(r >= 0);
344 assert_se(streq(s, "test"));
345
346 sd_bus_message_unref(reply);
347 reply = NULL;
348
349 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
350 assert_se(r >= 0);
351
352 assert_se(c->automatic_integer_property == 815);
353
354 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
355 assert_se(r >= 0);
356
357 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
358
359 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
360 assert_se(r >= 0);
361
362 r = sd_bus_message_read(reply, "s", &s);
363 assert_se(r >= 0);
364 fputs(s, stdout);
365
366 sd_bus_message_unref(reply);
367 reply = NULL;
368
369 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
370 assert_se(r >= 0);
371
372 r = sd_bus_message_read(reply, "s", &s);
373 assert_se(r >= 0);
374 log_info("read %s", s);
375
376 sd_bus_message_unref(reply);
377 reply = NULL;
378
379 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
380 assert_se(r >= 0);
381
382 r = sd_bus_message_read(reply, "s", &s);
383 assert_se(r >= 0);
384 fputs(s, stdout);
385
386 sd_bus_message_unref(reply);
387 reply = NULL;
388
389 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
390 assert_se(r >= 0);
391
392 r = sd_bus_message_read(reply, "s", &s);
393 assert_se(r >= 0);
394 fputs(s, stdout);
395
396 sd_bus_message_unref(reply);
397 reply = NULL;
398
399 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
400 assert_se(r >= 0);
401
402 r = sd_bus_message_read(reply, "s", &s);
403 assert_se(r >= 0);
404 fputs(s, stdout);
405
406 sd_bus_message_unref(reply);
407 reply = NULL;
408
409 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
410 assert_se(r >= 0);
411
412 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
413
414 sd_bus_message_unref(reply);
415 reply = NULL;
416
417 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
418 assert_se(r < 0);
419 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
420 sd_bus_error_free(&error);
421
422 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
423 assert_se(r < 0);
424 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
425 sd_bus_error_free(&error);
426
427 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
428 assert_se(r >= 0);
429
430 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
431
432 sd_bus_message_unref(reply);
433 reply = NULL;
434
435 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
436 assert_se(r >= 0);
437
438 r = sd_bus_process(bus, &reply);
439 assert_se(r > 0);
440
441 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
442 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
443
444 sd_bus_message_unref(reply);
445 reply = NULL;
446
447 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
448 assert_se(r >= 0);
449
450 r = sd_bus_process(bus, &reply);
451 assert_se(r > 0);
452
453 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
454 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
455
456 sd_bus_message_unref(reply);
457 reply = NULL;
458
459 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
460 assert_se(r >= 0);
461
462 r = sd_bus_process(bus, &reply);
463 assert_se(r > 0);
464
465 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
466 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
467
468 sd_bus_message_unref(reply);
469 reply = NULL;
470
471 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
472 assert_se(r >= 0);
473
474 r = sd_bus_process(bus, &reply);
475 assert_se(r > 0);
476
477 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
478 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
479
480 sd_bus_message_unref(reply);
481 reply = NULL;
482
483 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
484 assert_se(r >= 0);
485
486 r = sd_bus_process(bus, &reply);
487 assert_se(r > 0);
488
489 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
490 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
491
492 sd_bus_message_unref(reply);
493 reply = NULL;
494
495 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
496 assert_se(r >= 0);
497
498 r = sd_bus_process(bus, &reply);
499 assert_se(r > 0);
500
501 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
502 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
503
504 sd_bus_message_unref(reply);
505 reply = NULL;
506
507 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
508 assert_se(r >= 0);
509
510 sd_bus_flush(bus);
511
512 return 0;
513 }
514
515 int main(int argc, char *argv[]) {
516 struct context c = {};
517 pthread_t s;
518 void *p;
519 int r, q;
520
521 zero(c);
522
523 c.automatic_integer_property = 4711;
524 assert_se(c.automatic_string_property = strdup("dudeldu"));
525
526 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
527
528 r = pthread_create(&s, NULL, server, &c);
529 if (r != 0)
530 return -r;
531
532 r = client(&c);
533
534 q = pthread_join(s, &p);
535 if (q != 0)
536 return -q;
537
538 if (r < 0)
539 return r;
540
541 if (PTR_TO_INT(p) < 0)
542 return PTR_TO_INT(p);
543
544 free(c.something);
545 free(c.automatic_string_property);
546
547 return EXIT_SUCCESS;
548 }