chiark / gitweb /
nss-mymachines: map userns users of containers to real user names
[elogind.git] / src / libelogind / 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-util.h"
34 #include "bus-dump.h"
35
36 struct context {
37         int fds[2];
38         bool quit;
39         char *something;
40         char *automatic_string_property;
41         uint32_t automatic_integer_property;
42 };
43
44 static int something_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
45         struct context *c = userdata;
46         const char *s;
47         char *n = NULL;
48         int r;
49
50         r = sd_bus_message_read(m, "s", &s);
51         assert_se(r > 0);
52
53         n = strjoin("<<<", s, ">>>", NULL);
54         assert_se(n);
55
56         free(c->something);
57         c->something = n;
58
59         log_info("AlterSomething() called, got %s, returning %s", s, n);
60
61         /* This should fail, since the return type doesn't match */
62         assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
63
64         r = sd_bus_reply_method_return(m, "s", n);
65         assert_se(r >= 0);
66
67         return 1;
68 }
69
70 static int exit_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
71         struct context *c = userdata;
72         int r;
73
74         c->quit = true;
75
76         log_info("Exit called");
77
78         r = sd_bus_reply_method_return(m, "");
79         assert_se(r >= 0);
80
81         return 1;
82 }
83
84 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) {
85         struct context *c = userdata;
86         int r;
87
88         log_info("property get for %s called, returning \"%s\".", property, c->something);
89
90         r = sd_bus_message_append(reply, "s", c->something);
91         assert_se(r >= 0);
92
93         return 1;
94 }
95
96 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) {
97         struct context *c = userdata;
98         const char *s;
99         char *n;
100         int r;
101
102         log_info("property set for %s called", property);
103
104         r = sd_bus_message_read(value, "s", &s);
105         assert_se(r >= 0);
106
107         n = strdup(s);
108         assert_se(n);
109
110         free(c->something);
111         c->something = n;
112
113         return 1;
114 }
115
116 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) {
117         _cleanup_free_ char *s = NULL;
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(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0);
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), m->path, "org.freedesktop.systemd.test", 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), m->path, "org.freedesktop.systemd.test", 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), m->path) >= 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), m->path) >= 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 void *server(void *p) {
232         struct context *c = p;
233         sd_bus *bus = NULL;
234         sd_id128_t id;
235         int r;
236
237         c->quit = false;
238
239         assert_se(sd_id128_randomize(&id) >= 0);
240
241         assert_se(sd_bus_new(&bus) >= 0);
242         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
243         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
244
245         assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
246         assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
247         assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
248         assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
249         assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
250
251         assert_se(sd_bus_start(bus) >= 0);
252
253         log_error("Entering event loop on server");
254
255         while (!c->quit) {
256                 log_error("Loop!");
257
258                 r = sd_bus_process(bus, NULL);
259                 if (r < 0) {
260                         log_error_errno(r, "Failed to process requests: %m");
261                         goto fail;
262                 }
263
264                 if (r == 0) {
265                         r = sd_bus_wait(bus, (uint64_t) -1);
266                         if (r < 0) {
267                                 log_error_errno(r, "Failed to wait: %m");
268                                 goto fail;
269                         }
270
271                         continue;
272                 }
273         }
274
275         r = 0;
276
277 fail:
278         if (bus) {
279                 sd_bus_flush(bus);
280                 sd_bus_unref(bus);
281         }
282
283         return INT_TO_PTR(r);
284 }
285
286 static int client(struct context *c) {
287         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
288         _cleanup_bus_unref_ sd_bus *bus = NULL;
289         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
290         const char *s;
291         int r;
292
293         assert_se(sd_bus_new(&bus) >= 0);
294         assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
295         assert_se(sd_bus_start(bus) >= 0);
296
297         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
298         assert_se(r >= 0);
299
300         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
301         assert_se(r >= 0);
302
303         r = sd_bus_message_read(reply, "s", &s);
304         assert_se(r >= 0);
305         assert_se(streq(s, "<<<hallo>>>"));
306
307         sd_bus_message_unref(reply);
308         reply = NULL;
309
310         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
311         assert_se(r < 0);
312         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
313
314         sd_bus_error_free(&error);
315
316         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
317         assert_se(r < 0);
318         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
319
320         sd_bus_error_free(&error);
321
322         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
323         assert_se(r >= 0);
324
325         r = sd_bus_message_read(reply, "s", &s);
326         assert_se(r >= 0);
327         assert_se(streq(s, "<<<hallo>>>"));
328
329         sd_bus_message_unref(reply);
330         reply = NULL;
331
332         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
333         assert_se(r >= 0);
334
335         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
336         assert_se(r >= 0);
337
338         r = sd_bus_message_read(reply, "s", &s);
339         assert_se(r >= 0);
340         assert_se(streq(s, "test"));
341
342         sd_bus_message_unref(reply);
343         reply = NULL;
344
345         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
346         assert_se(r >= 0);
347
348         assert_se(c->automatic_integer_property == 815);
349
350         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
351         assert_se(r >= 0);
352
353         assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
354
355         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
356         assert_se(r >= 0);
357
358         r = sd_bus_message_read(reply, "s", &s);
359         assert_se(r >= 0);
360         fputs(s, stdout);
361
362         sd_bus_message_unref(reply);
363         reply = NULL;
364
365         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
366         assert_se(r >= 0);
367
368         r = sd_bus_message_read(reply, "s", &s);
369         assert_se(r >= 0);
370         log_info("read %s", s);
371
372         sd_bus_message_unref(reply);
373         reply = NULL;
374
375         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
376         assert_se(r >= 0);
377
378         r = sd_bus_message_read(reply, "s", &s);
379         assert_se(r >= 0);
380         fputs(s, stdout);
381
382         sd_bus_message_unref(reply);
383         reply = NULL;
384
385         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "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/a", "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", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
406         assert_se(r >= 0);
407
408         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
409
410         sd_bus_message_unref(reply);
411         reply = NULL;
412
413         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
414         assert_se(r < 0);
415         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
416         sd_bus_error_free(&error);
417
418         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
419         assert_se(r < 0);
420         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
421         sd_bus_error_free(&error);
422
423         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
424         assert_se(r >= 0);
425
426         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
427
428         sd_bus_message_unref(reply);
429         reply = NULL;
430
431         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
432         assert_se(r >= 0);
433
434         r = sd_bus_process(bus, &reply);
435         assert_se(r > 0);
436
437         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
438         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
439
440         sd_bus_message_unref(reply);
441         reply = NULL;
442
443         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
444         assert_se(r >= 0);
445
446         r = sd_bus_process(bus, &reply);
447         assert_se(r > 0);
448
449         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
450         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
451
452         sd_bus_message_unref(reply);
453         reply = NULL;
454
455         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
456         assert_se(r >= 0);
457
458         r = sd_bus_process(bus, &reply);
459         assert_se(r > 0);
460
461         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
462         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
463
464         sd_bus_message_unref(reply);
465         reply = NULL;
466
467         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
468         assert_se(r >= 0);
469
470         r = sd_bus_process(bus, &reply);
471         assert_se(r > 0);
472
473         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
474         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
475
476         sd_bus_message_unref(reply);
477         reply = NULL;
478
479         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
480         assert_se(r >= 0);
481
482         r = sd_bus_process(bus, &reply);
483         assert_se(r > 0);
484
485         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
486         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
487
488         sd_bus_message_unref(reply);
489         reply = NULL;
490
491         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
492         assert_se(r >= 0);
493
494         r = sd_bus_process(bus, &reply);
495         assert_se(r > 0);
496
497         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
498         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
499
500         sd_bus_message_unref(reply);
501         reply = NULL;
502
503         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
504         assert_se(r >= 0);
505
506         sd_bus_flush(bus);
507
508         return 0;
509 }
510
511 int main(int argc, char *argv[]) {
512         struct context c = {};
513         pthread_t s;
514         void *p;
515         int r, q;
516
517         zero(c);
518
519         c.automatic_integer_property = 4711;
520         assert_se(c.automatic_string_property = strdup("dudeldu"));
521
522         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
523
524         r = pthread_create(&s, NULL, server, &c);
525         if (r != 0)
526                 return -r;
527
528         r = client(&c);
529
530         q = pthread_join(s, &p);
531         if (q != 0)
532                 return -q;
533
534         if (r < 0)
535                 return r;
536
537         if (PTR_TO_INT(p) < 0)
538                 return PTR_TO_INT(p);
539
540         free(c.something);
541         free(c.automatic_string_property);
542
543         return EXIT_SUCCESS;
544 }