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