1SD_BUS_ADD_OBJECT(3) sd_bus_add_object SD_BUS_ADD_OBJECT(3)
2
3
4
6 sd_bus_add_object, sd_bus_add_fallback, sd_bus_add_object_vtable,
7 sd_bus_add_fallback_vtable, sd_bus_add_filter, SD_BUS_VTABLE_START,
8 SD_BUS_VTABLE_END, SD_BUS_METHOD_WITH_NAMES_OFFSET,
9 SD_BUS_METHOD_WITH_NAMES, SD_BUS_METHOD_WITH_OFFSET, SD_BUS_METHOD,
10 SD_BUS_SIGNAL_WITH_NAMES, SD_BUS_SIGNAL, SD_BUS_WRITABLE_PROPERTY,
11 SD_BUS_PROPERTY, SD_BUS_PARAM - Declare properties and methods for a
12 D-Bus path
13
15 #include <systemd/sd-bus-vtable.h>
16
17
18 typedef int (*sd_bus_message_handler_t)(sd_bus_message *m,
19 void *userdata,
20 sd_bus_error *ret_error);
21
22 typedef int (*sd_bus_property_get_t)(sd_bus *bus, const char *path,
23 const char *interface,
24 const char *property,
25 sd_bus_message *reply,
26 void *userdata,
27 sd_bus_error *ret_error);
28
29 typedef int (*sd_bus_property_set_t)(sd_bus *bus, const char *path,
30 const char *interface,
31 const char *property,
32 sd_bus_message *value,
33 void *userdata,
34 sd_bus_error *ret_error);
35
36 typedef int (*sd_bus_object_find_t)(const char *path,
37 const char *interface,
38 void *userdata, void **ret_found,
39 sd_bus_error *ret_error);
40
41 int sd_bus_add_object(sd_bus *bus, sd_bus_slot **slot,
42 const char *path,
43 sd_bus_message_handler_t callback,
44 void *userdata);
45
46 int sd_bus_add_fallback(sd_bus *bus, sd_bus_slot **slot,
47 const char *path,
48 sd_bus_message_handler_t callback,
49 void *userdata);
50
51 int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot,
52 const char *path, const char *interface,
53 const sd_bus_vtable *vtable,
54 void *userdata);
55
56 int sd_bus_add_fallback_vtable(sd_bus *bus, sd_bus_slot **slot,
57 const char *prefix,
58 const char *interface,
59 const sd_bus_vtable *vtable,
60 sd_bus_object_find_t find,
61 void *userdata);
62
63 int sd_bus_add_filter(sd_bus *bus, sd_bus_slot **slot,
64 sd_bus_message_handler_t callback,
65 void *userdata);
66
67 SD_BUS_VTABLE_START(flags)
68
69 SD_BUS_VTABLE_END
70
71 SD_BUS_METHOD_WITH_ARGS_OFFSET( member, args, result, handler, offset,
72 flags)
73
74 SD_BUS_METHOD_WITH_ARGS( member, args, result, handler, flags)
75
76 SD_BUS_METHOD_WITH_NAMES_OFFSET( member, signature, in_names, result,
77 out_names, handler, offset, flags)
78
79 SD_BUS_METHOD_WITH_NAMES( member, signature, in_names, result,
80 out_names, handler, flags)
81
82 SD_BUS_METHOD_WITH_OFFSET( member, signature, result, handler, offset,
83 flags)
84
85 SD_BUS_METHOD( member, signature, result, handler, flags)
86
87 SD_BUS_SIGNAL_WITH_ARGS( member, args, flags)
88
89 SD_BUS_SIGNAL_WITH_NAMES( member, signature, names, flags)
90
91 SD_BUS_SIGNAL( member, signature, flags)
92
93 SD_BUS_WRITABLE_PROPERTY( member, signature, get, set, offset, flags)
94
95 SD_BUS_PROPERTY( member, signature, get, offset, flags)
96
97 SD_BUS_PARAM(name) SD_BUS_ARGS(...) SD_BUS_RESULT(...) SD_BUS_NO_ARGS
98 SD_BUS_NO_RESULT
99
101 sd_bus_add_object_vtable() is used to declare attributes for the object
102 path path connected to the bus connection bus under the interface
103 interface. The table vtable may contain property declarations using
104 SD_BUS_PROPERTY() or SD_BUS_WRITABLE_PROPERTY(), method declarations
105 using SD_BUS_METHOD(), SD_BUS_METHOD_WITH_NAMES(),
106 SD_BUS_METHOD_WITH_OFFSET(), or SD_BUS_METHOD_WITH_NAMES_OFFSET(), and
107 signal declarations using SD_BUS_SIGNAL_WITH_NAMES() or
108 SD_BUS_SIGNAL(), see below. The userdata parameter contains a pointer
109 that will be passed to various callback functions. It may be specified
110 as NULL if no value is necessary. An interface can have any number of
111 vtables attached to it.
112
113 sd_bus_add_fallback_vtable() is similar to sd_bus_add_object_vtable(),
114 but is used to register "fallback" attributes. When looking for an
115 attribute declaration, bus object paths registered with
116 sd_bus_add_object_vtable() are checked first. If no match is found, the
117 fallback vtables are checked for each prefix of the bus object path,
118 i.e. with the last slash-separated components successively removed.
119 This allows the vtable to be used for an arbitrary number of
120 dynamically created objects.
121
122 Parameter find is a function which is used to locate the target object
123 based on the bus object path path. It must return 1 and set the
124 ret_found output parameter if the object is found, return 0 if the
125 object was not found, and return a negative errno-style error code or
126 initialize the error structure ret_error on error. The pointer passed
127 in ret_found will be used as the userdata parameter for the callback
128 functions (offset by the offset offsets as specified in the vtable
129 entries).
130
131 sd_bus_add_object() attaches a callback directly to the object path
132 path. An object path can have any number of callbacks attached to it.
133 Each callback is prepended to the list of callbacks which are always
134 called in order. sd_bus_add_fallback() is similar to
135 sd_bus_add_object() but applies to fallback paths instead.
136
137 sd_bus_add_filter() installs a callback that is invoked for each
138 incoming D-Bus message. Filters can be used to handle logic common to
139 all messages received by a service (e.g. authentication or
140 authorization).
141
142 When a request is received, any associated callbacks are called
143 sequentially until a callback returns a non-zero integer. Return zero
144 from a callback to give other callbacks the chance to process the
145 request. Callbacks are called in the following order: first, global
146 callbacks installed with sd_bus_add_filter() are called. Second,
147 callbacks attached directly to the request object path are called,
148 followed by any D-Bus method callbacks attached to the request object
149 path, interface and member. Finally, the property callbacks attached to
150 the request object path, interface and member are called. If the final
151 callback returns zero, an error reply is sent back to the caller
152 indicating no matching object for the request was found.
153
154 Note that you can return a positive integer from a callback without
155 immediately sending a reply. This informs sd-bus this callback will
156 take responsibility for replying to the request without forcing the
157 callback to produce a reply immediately. This allows a callback to
158 perform any number of asynchronous operations required to construct a
159 reply. However, if producing a reply takes too long, the method call
160 will time out at the caller.
161
162 If a callback was invoked to handle a request that expects a reply and
163 the callback returns a negative value, the value is interpreted as a
164 negative errno-style error code and sent back to the caller as a D-Bus
165 error as if sd_bus_reply_method_errno(3) was called. Additionally, all
166 callbacks take a sd_bus_error output parameter that can be used to
167 provide more detailed error information. If ret_error is set when the
168 callback finishes, the corresponding D-Bus error is sent back to the
169 caller as if sd_bus_reply_method_error(3) was called. Any error stored
170 in ret_error takes priority over any negative values returned by the
171 same callback when determining which error to send back to the caller.
172 Use sd_bus_error_set(3) or one of its variants to set ret_error and
173 return a negative integer from a callback with a single function call.
174 To send an error reply after a callback has already finished, use
175 sd_bus_reply_method_errno(3) or one of its variants.
176
177 For all functions, a match slot is created internally. If the output
178 parameter slot is NULL, a "floating" slot object is created, see
179 sd_bus_slot_set_floating(3). Otherwise, a pointer to the slot object is
180 returned. In that case, the reference to the slot object should be
181 dropped when the vtable is not needed anymore, see
182 sd_bus_slot_unref(3).
183
184 The sd_bus_vtable array
185 The array consists of the structures of type sd_bus_vtable, but it
186 should never be filled in manually, but through one of the following
187 macros:
188
189 SD_BUS_VTABLE_START(), SD_BUS_VTABLE_END
190 Those must always be the first and last element.
191
192 SD_BUS_METHOD_WITH_ARGS_OFFSET(), SD_BUS_METHOD_WITH_ARGS()
193 Declare a D-Bus method with the name member, arguments args and
194 result result. args expects a sequence of argument type/name pairs
195 wrapped in the SD_BUS_ARGS() macro. The elements at even indices in
196 this list describe the types of the method's arguments. The
197 method's parameter signature is the concatenation of all the string
198 literals at even indices in args. If a method has no parameters,
199 pass SD_BUS_NO_ARGS to args. The elements at uneven indices
200 describe the names of the method's arguments. result expects a
201 sequence of type/name pairs wrapped in the SD_BUS_RESULT() macro in
202 the same format as SD_BUS_ARGS(). The method's result signature is
203 the concatenation of all the string literals at even indices in
204 result. If a method has no result, pass SD_BUS_NO_RESULT to result.
205 Note that argument types are expected to be quoted string literals
206 and argument names are expected to be unquoted string literals. See
207 below for a complete example.
208
209 The handler function handler must be of type
210 sd_bus_message_handler_t. It will be called to handle the incoming
211 messages that call this method. It receives a pointer that is the
212 userdata parameter passed to the registration function offset by
213 offset bytes. This may be used to pass pointers to different fields
214 in the same data structure to different methods in the same vtable.
215 To send a reply from handler, call sd_bus_reply_method_return(3)
216 with the message the callback was invoked with. Parameter flags is
217 a combination of flags, see below.
218
219 SD_BUS_METHOD_WITH_ARGS() is a shorthand for calling
220 SD_BUS_METHOD_WITH_ARGS_OFFSET() with an offset of zero.
221
222 SD_BUS_METHOD_WITH_NAMES_OFFSET(), SD_BUS_METHOD_WITH_NAMES(),
223 SD_BUS_METHOD_WITH_OFFSET(), SD_BUS_METHOD()
224 Declare a D-Bus method with the name member, parameter signature
225 signature, result signature result. Parameters in_names and
226 out_names specify the argument names of the input and output
227 arguments in the function signature. in_names and out_names should
228 be created using the SD_BUS_PARAM() macro, see below. In all other
229 regards, this macro behaves exactly the same as
230 SD_BUS_METHOD_WITH_ARGS_OFFSET().
231
232 SD_BUS_METHOD_WITH_NAMES(), SD_BUS_METHOD_WITH_OFFSET(), and
233 SD_BUS_METHOD() are variants which specify zero offset (userdata
234 parameter is passed with no change), leave the names unset (i.e. no
235 parameter names), or both.
236
237 Prefer using SD_BUS_METHOD_WITH_ARGS_OFFSET() and
238 SD_BUS_METHOD_WITH_ARGS() over these macros as they allow
239 specifying argument types and names next to each other which is
240 less error-prone than first specifying all argument types followed
241 by specifying all argument names.
242
243 SD_BUS_SIGNAL_WITH_ARGS()
244 Declare a D-Bus signal with the name member and arguments args.
245 args expects a sequence of argument type/name pairs wrapped in the
246 SD_BUS_ARGS() macro. The elements at even indices in this list
247 describe the types of the signal's arguments. The signal's
248 parameter signature is the concatenation of all the string literals
249 at even indices in args. If a signal has no parameters, pass
250 SD_BUS_NO_ARGS to args. The elements at uneven indices describe the
251 names of the signal's arguments. Parameter flags is a combination
252 of flags. See below for a complete example.
253
254 SD_BUS_SIGNAL_WITH_NAMES(), SD_BUS_SIGNAL()
255 Declare a D-Bus signal with the name member, parameter signature
256 signature, and argument names names. names should be created using
257 the SD_BUS_PARAM() macro, see below. Parameter flags is a
258 combination of flags, see below.
259
260 SD_BUS_SIGNAL() is equivalent to SD_BUS_SIGNAL_WITH_NAMES() with
261 the names parameter unset (i.e. no parameter names).
262
263 Prefer using SD_BUS_SIGNAL_WITH_ARGS() over these macros as it
264 allows specifying argument types and names next to each other which
265 is less error-prone than first specifying all argument types
266 followed by specifying all argument names.
267
268 SD_BUS_WRITABLE_PROPERTY(), SD_BUS_PROPERTY()
269 Declare a D-Bus property with the name member and value signature
270 signature. Parameters get and set are the getter and setter
271 methods. They are called with a pointer that is the userdata
272 parameter passed to the registration function offset by offset
273 bytes. This may be used pass pointers to different fields in the
274 same data structure to different setters and getters in the same
275 vtable. Parameter flags is a combination of flags, see below.
276
277 The setter and getter methods may be omitted (specified as NULL),
278 if the property is one of the basic types or "as" in case of
279 read-only properties. In those cases, the userdata and offset
280 parameters must together point to a valid variable of the
281 corresponding type. A default setter and getter will be provided,
282 which simply copy the argument between this variable and the
283 message.
284
285 SD_BUS_PROPERTY() is used to define a read-only property.
286
287 SD_BUS_PARAM()
288 Parameter names should be wrapped in this macro, see the example
289 below.
290
291 Flags
292 The flags parameter is used to specify a combination of D-Bus
293 annotations[1].
294
295 SD_BUS_VTABLE_DEPRECATED
296 Mark this vtable entry as deprecated using the
297 org.freedesktop.DBus.Deprecated annotation in introspection data.
298 If specified for SD_BUS_VTABLE_START(), the annotation is applied
299 to the enclosing interface.
300
301 SD_BUS_VTABLE_HIDDEN
302 Make this vtable entry hidden. It will not be shown in
303 introspection data. If specified for SD_BUS_VTABLE_START(), all
304 entries in the array are hidden.
305
306 SD_BUS_VTABLE_UNPRIVILEGED
307 Mark this vtable entry as unprivileged. If not specified, the
308 org.freedesktop.systemd1.Privileged annotation with value "true"
309 will be shown in introspection data.
310
311 SD_BUS_VTABLE_METHOD_NO_REPLY
312 Mark his vtable entry as a method that will not return a reply
313 using the org.freedesktop.DBus.Method.NoReply annotation in
314 introspection data.
315
316 SD_BUS_VTABLE_PROPERTY_CONST, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE,
317 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
318 Those three flags correspond to different values of the
319 org.freedesktop.DBus.Property.EmitsChangedSignal annotation, which
320 specifies whether the
321 org.freedesktop.DBus.Properties.PropertiesChanged signal is emitted
322 whenever the property changes. SD_BUS_VTABLE_PROPERTY_CONST
323 corresponds to const and means that the property never changes
324 during the lifetime of the object it belongs to, so no signal needs
325 to be emitted. SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE corresponds to
326 true and means that the signal is emitted.
327 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION corresponds to
328 invalidates and means that the signal is emitted, but the value is
329 not included in the signal.
330
331 SD_BUS_VTABLE_PROPERTY_EXPLICIT
332 Mark this vtable property entry as requiring explicit request to
333 for the value to be shown (generally because the value is large or
334 slow to calculate). This entry cannot be combined with
335 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, and will not be shown in
336 property listings by default (e.g. busctl introspect). This
337 corresponds to the org.freedesktop.systemd1.Explicit annotation in
338 introspection data.
339
340 SD_BUS_VTABLE_SENSITIVE
341 Mark this vtable method entry as processing sensitive data. When
342 set, incoming method call messages and their outgoing reply
343 messages are marked as sensitive using sd_bus_message_sensitive(3),
344 so that they are erased from memory when freed.
345
346 SD_BUS_VTABLE_ABSOLUTE_OFFSET
347 Mark this vtable method or property entry so that the user data
348 pointer passed to its associated handler functions is determined
349 slightly differently: instead of adding the offset parameter of the
350 entry to the user data pointer specified during vtable
351 registration, the offset is passed directly, converted to a
352 pointer, without taking the user data pointer specified during
353 vtable registration into account.
354
356 Example 1. Create a simple listener on the bus
357
358 #include <errno.h>
359 #include <stdbool.h>
360 #include <stddef.h>
361 #include <stdlib.h>
362 #include <stdio.h>
363 #include <systemd/sd-bus.h>
364
365 #define _cleanup_(f) __attribute__((cleanup(f)))
366
367 typedef struct object {
368 char *name;
369 uint32_t number;
370 } object;
371
372 static int method(sd_bus_message *m, void *userdata, sd_bus_error *error) {
373 printf("Got called with userdata=%p\n", userdata);
374 return 1;
375 }
376
377 static const sd_bus_vtable vtable[] = {
378 SD_BUS_VTABLE_START(0),
379 SD_BUS_METHOD(
380 "Method1", "s", "s", method, 0),
381 SD_BUS_METHOD_WITH_NAMES_OFFSET(
382 "Method2",
383 "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
384 "s", SD_BUS_PARAM(returnstring),
385 method, offsetof(object, number),
386 SD_BUS_VTABLE_DEPRECATED),
387 SD_BUS_METHOD_WITH_ARGS_OFFSET(
388 "Method3",
389 SD_BUS_ARGS("s", string, "o", path),
390 SD_BUS_RESULT("s", returnstring),
391 method, offsetof(object, number),
392 SD_BUS_VTABLE_UNPRIVILEGED),
393 SD_BUS_METHOD_WITH_ARGS(
394 "Method4",
395 SD_BUS_NO_ARGS,
396 SD_BUS_NO_RESULT,
397 method,
398 SD_BUS_VTABLE_UNPRIVILEGED),
399 SD_BUS_SIGNAL(
400 "Signal1",
401 "so",
402 0),
403 SD_BUS_SIGNAL_WITH_NAMES(
404 "Signal2",
405 "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
406 0),
407 SD_BUS_SIGNAL_WITH_ARGS(
408 "Signal3",
409 SD_BUS_ARGS("s", string, "o", path),
410 0),
411 SD_BUS_WRITABLE_PROPERTY(
412 "AutomaticStringProperty", "s", NULL, NULL,
413 offsetof(object, name),
414 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
415 SD_BUS_WRITABLE_PROPERTY(
416 "AutomaticIntegerProperty", "u", NULL, NULL,
417 offsetof(object, number),
418 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
419 SD_BUS_VTABLE_END
420 };
421
422 #define check(x) ({ \
423 int r = x; \
424 errno = r < 0 ? -r : 0; \
425 printf(#x ": %m\n"); \
426 if (r < 0) \
427 return EXIT_FAILURE; \
428 })
429
430 int main(int argc, char **argv) {
431 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
432
433 sd_bus_default(&bus);
434
435 object object = { .number = 666 };
436 check((object.name = strdup("name")) != NULL);
437
438 check(sd_bus_add_object_vtable(bus, NULL, "/object",
439 "org.freedesktop.systemd.VtableExample",
440 vtable,
441 &object));
442
443 for (;;) {
444 check(sd_bus_wait(bus, UINT64_MAX));
445 check(sd_bus_process(bus, NULL));
446 }
447
448 free(object.name);
449
450 return 0;
451 }
452
453 This creates a simple client on the bus (the user bus, when run as
454 normal user). We may use the D-Bus
455 org.freedesktop.DBus.Introspectable.Introspect call to acquire the XML
456 description of the interface:
457
458 <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
459 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
460 <node>
461 <interface name="org.freedesktop.DBus.Peer">
462 <method name="Ping"/>
463 <method name="GetMachineId">
464 <arg type="s" name="machine_uuid" direction="out"/>
465 </method>
466 </interface>
467 <interface name="org.freedesktop.DBus.Introspectable">
468 <method name="Introspect">
469 <arg name="data" type="s" direction="out"/>
470 </method>
471 </interface>
472 <interface name="org.freedesktop.DBus.Properties">
473 <method name="Get">
474 <arg name="interface" direction="in" type="s"/>
475 <arg name="property" direction="in" type="s"/>
476 <arg name="value" direction="out" type="v"/>
477 </method>
478 <method name="GetAll">
479 <arg name="interface" direction="in" type="s"/>
480 <arg name="properties" direction="out" type="a{sv}"/>
481 </method>
482 <method name="Set">
483 <arg name="interface" direction="in" type="s"/>
484 <arg name="property" direction="in" type="s"/>
485 <arg name="value" direction="in" type="v"/>
486 </method>
487 <signal name="PropertiesChanged">
488 <arg type="s" name="interface"/>
489 <arg type="a{sv}" name="changed_properties"/>
490 <arg type="as" name="invalidated_properties"/>
491 </signal>
492 </interface>
493 <interface name="org.freedesktop.systemd.VtableExample">
494 <method name="Method1">
495 <arg type="s" direction="in"/>
496 <arg type="s" direction="out"/>
497 </method>
498 <method name="Method2">
499 <arg type="s" name="string" direction="in"/>
500 <arg type="o" name="path" direction="in"/>
501 <arg type="s" name="returnstring" direction="out"/>
502 <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
503 </method>
504 <property name="AutomaticStringProperty" type="s" access="readwrite">
505 </property>
506 <property name="AutomaticIntegerProperty" type="u" access="readwrite">
507 <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
508 </property>
509 </interface>
510 </node>
511
512
514 On success, sd_bus_add_object_vtable() and sd_bus_add_fallback_vtable()
515 return a non-negative integer. On failure, they return a negative
516 errno-style error code.
517
518 Errors
519 Returned errors may indicate the following problems:
520
521 -EINVAL
522 One of the required parameters is NULL or invalid. A reserved D-Bus
523 interface was passed as the interface parameter.
524
525 -ENOPKG
526 The bus cannot be resolved.
527
528 -ECHILD
529 The bus was created in a different process.
530
531 -ENOMEM
532 Memory allocation failed.
533
534 -EPROTOTYPE
535 sd_bus_add_object_vtable and sd_bus_add_fallback_vtable have been
536 both called for the same bus object path, which is not allowed.
537
538 -EEXIST
539 This vtable has already been registered for this interface and
540 path.
541
543 These APIs are implemented as a shared library, which can be compiled
544 and linked to with the libsystemd pkg-config(1) file.
545
547 sd-bus(3), busctl(1), sd_bus_emit_properties_changed(3),
548 sd_bus_emit_object_added(3)
549
551 1. D-Bus annotations
552 https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
553
554
555
556systemd 246 SD_BUS_ADD_OBJECT(3)