]> git.ipfire.org Git - people/ms/systemd.git/blob - dbus.c
cgroup: add cgroupsification
[people/ms/systemd.git] / dbus.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <dbus/dbus.h>
23
24 #include <sys/epoll.h>
25 #include <sys/timerfd.h>
26 #include <errno.h>
27 #include <unistd.h>
28
29 #include "dbus.h"
30 #include "log.h"
31 #include "strv.h"
32 #include "cgroup.h"
33
34 static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
35 Manager *m = data;
36
37 assert(bus);
38 assert(m);
39 assert(m->bus == bus);
40
41 m->request_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
42 }
43
44 static void system_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
45 Manager *m = data;
46
47 assert(bus);
48 assert(m);
49 assert(m->system_bus == bus);
50
51 m->request_system_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
52 }
53
54 static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
55 unsigned flags;
56 uint32_t events = 0;
57
58 assert(bus_watch);
59
60 /* no watch flags for disabled watches */
61 if (!dbus_watch_get_enabled(bus_watch))
62 return 0;
63
64 flags = dbus_watch_get_flags(bus_watch);
65
66 if (flags & DBUS_WATCH_READABLE)
67 events |= EPOLLIN;
68 if (flags & DBUS_WATCH_WRITABLE)
69 events |= EPOLLOUT;
70
71 return events | EPOLLHUP | EPOLLERR;
72 }
73
74 static unsigned events_to_bus_flags(uint32_t events) {
75 unsigned flags = 0;
76
77 if (events & EPOLLIN)
78 flags |= DBUS_WATCH_READABLE;
79 if (events & EPOLLOUT)
80 flags |= DBUS_WATCH_WRITABLE;
81 if (events & EPOLLHUP)
82 flags |= DBUS_WATCH_HANGUP;
83 if (events & EPOLLERR)
84 flags |= DBUS_WATCH_ERROR;
85
86 return flags;
87 }
88
89 void bus_watch_event(Manager *m, Watch *w, int events) {
90 assert(m);
91 assert(w);
92
93 /* This is called by the event loop whenever there is
94 * something happening on D-Bus' file handles. */
95
96 if (!dbus_watch_get_enabled(w->data.bus_watch))
97 return;
98
99 dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
100 }
101
102 static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
103 Manager *m = data;
104 Watch *w;
105 struct epoll_event ev;
106
107 assert(bus_watch);
108 assert(m);
109
110 if (!(w = new0(Watch, 1)))
111 return FALSE;
112
113 w->fd = dbus_watch_get_unix_fd(bus_watch);
114 w->type = WATCH_DBUS_WATCH;
115 w->data.bus_watch = bus_watch;
116
117 zero(ev);
118 ev.events = bus_flags_to_events(bus_watch);
119 ev.data.ptr = w;
120
121 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
122
123 if (errno != EEXIST) {
124 free(w);
125 return FALSE;
126 }
127
128 /* Hmm, bloody D-Bus creates multiple watches on the
129 * same fd. epoll() does not like that. As a dirty
130 * hack we simply dup() the fd and hence get a second
131 * one we can safely add to the epoll(). */
132
133 if ((w->fd = dup(w->fd)) < 0) {
134 free(w);
135 return FALSE;
136 }
137
138 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
139 free(w);
140 close_nointr_nofail(w->fd);
141 return FALSE;
142 }
143
144 w->fd_is_dupped = true;
145 }
146
147 dbus_watch_set_data(bus_watch, w, NULL);
148
149 return TRUE;
150 }
151
152 static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
153 Manager *m = data;
154 Watch *w;
155
156 assert(bus_watch);
157 assert(m);
158
159 if (!(w = dbus_watch_get_data(bus_watch)))
160 return;
161
162 assert(w->type == WATCH_DBUS_WATCH);
163 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
164
165 if (w->fd_is_dupped)
166 close_nointr_nofail(w->fd);
167
168 free(w);
169 }
170
171 static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
172 Manager *m = data;
173 Watch *w;
174 struct epoll_event ev;
175
176 assert(bus_watch);
177 assert(m);
178
179 assert_se(w = dbus_watch_get_data(bus_watch));
180 assert(w->type == WATCH_DBUS_WATCH);
181
182 zero(ev);
183 ev.events = bus_flags_to_events(bus_watch);
184 ev.data.ptr = w;
185
186 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
187 }
188
189 static int bus_timeout_arm(Manager *m, Watch *w) {
190 struct itimerspec its;
191
192 assert(m);
193 assert(w);
194
195 zero(its);
196
197 if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
198 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
199 its.it_interval = its.it_interval;
200 }
201
202 if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
203 return -errno;
204
205 return 0;
206 }
207
208 void bus_timeout_event(Manager *m, Watch *w, int events) {
209 assert(m);
210 assert(w);
211
212 /* This is called by the event loop whenever there is
213 * something happening on D-Bus' file handles. */
214
215 if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
216 return;
217
218 dbus_timeout_handle(w->data.bus_timeout);
219 }
220
221 static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
222 Manager *m = data;
223 Watch *w;
224 struct epoll_event ev;
225
226 assert(timeout);
227 assert(m);
228
229 if (!(w = new0(Watch, 1)))
230 return FALSE;
231
232 if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
233 goto fail;
234
235 w->type = WATCH_DBUS_TIMEOUT;
236 w->data.bus_timeout = timeout;
237
238 if (bus_timeout_arm(m, w) < 0)
239 goto fail;
240
241 zero(ev);
242 ev.events = EPOLLIN;
243 ev.data.ptr = w;
244
245 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
246 goto fail;
247
248 dbus_timeout_set_data(timeout, w, NULL);
249
250 return TRUE;
251
252 fail:
253 if (w->fd >= 0)
254 close_nointr_nofail(w->fd);
255
256 free(w);
257 return FALSE;
258 }
259
260 static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
261 Manager *m = data;
262 Watch *w;
263
264 assert(timeout);
265 assert(m);
266
267 if (!(w = dbus_timeout_get_data(timeout)))
268 return;
269
270 assert(w->type == WATCH_DBUS_TIMEOUT);
271 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
272 close_nointr_nofail(w->fd);
273 free(w);
274 }
275
276 static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
277 Manager *m = data;
278 Watch *w;
279 int r;
280
281 assert(timeout);
282 assert(m);
283
284 assert_se(w = dbus_timeout_get_data(timeout));
285 assert(w->type == WATCH_DBUS_TIMEOUT);
286
287 if ((r = bus_timeout_arm(m, w)) < 0)
288 log_error("Failed to rearm timer: %s", strerror(-r));
289 }
290
291 static DBusHandlerResult bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
292 Manager *m = data;
293 DBusError error;
294
295 assert(connection);
296 assert(message);
297 assert(m);
298
299 dbus_error_init(&error);
300
301 /* log_debug("Got D-Bus request: %s.%s() on %s", */
302 /* dbus_message_get_interface(message), */
303 /* dbus_message_get_member(message), */
304 /* dbus_message_get_path(message)); */
305
306 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
307 log_error("Warning! D-Bus connection terminated.");
308
309 /* FIXME: we probably should restart D-Bus here */
310
311 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
312 const char *name, *old, *new;
313
314 if (!dbus_message_get_args(message, &error,
315 DBUS_TYPE_STRING, &name,
316 DBUS_TYPE_STRING, &old,
317 DBUS_TYPE_STRING, &new,
318 DBUS_TYPE_INVALID))
319 log_error("Failed to parse NameOwnerChanged message: %s", error.message);
320 else {
321 if (set_remove(m->subscribed, (char*) name))
322 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
323 }
324 }
325
326 dbus_error_free(&error);
327 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
328 }
329
330 static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
331 Manager *m = data;
332 DBusError error;
333
334 assert(connection);
335 assert(message);
336 assert(m);
337
338 dbus_error_init(&error);
339
340 /* log_debug("Got D-Bus request: %s.%s() on %s", */
341 /* dbus_message_get_interface(message), */
342 /* dbus_message_get_member(message), */
343 /* dbus_message_get_path(message)); */
344
345 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
346 log_error("Warning! D-Bus connection terminated.");
347
348 /* FIXME: we probably should restart D-Bus here */
349
350 } if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
351 const char *cgroup;
352
353 if (!dbus_message_get_args(message, &error,
354 DBUS_TYPE_STRING, &cgroup,
355 DBUS_TYPE_INVALID))
356 log_error("Failed to parse Released message: %s", error.message);
357 else
358 cgroup_notify_empty(m, cgroup);
359 }
360
361 dbus_error_free(&error);
362 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
363 }
364
365 unsigned bus_dispatch(Manager *m) {
366 assert(m);
367
368 if (m->request_bus_dispatch)
369 if (dbus_connection_dispatch(m->bus) == DBUS_DISPATCH_COMPLETE) {
370 m->request_bus_dispatch = false;
371 return 1;
372 }
373
374 if (m->request_system_bus_dispatch)
375 if (dbus_connection_dispatch(m->system_bus) == DBUS_DISPATCH_COMPLETE) {
376 m->request_system_bus_dispatch = false;
377 return 1;
378 }
379
380 return 0;
381 }
382
383 static int request_name(Manager *m) {
384 DBusMessage *message;
385 const char *name = "org.freedesktop.systemd1";
386 uint32_t flags = 0;
387
388 if (!(message = dbus_message_new_method_call(
389 DBUS_SERVICE_DBUS,
390 DBUS_PATH_DBUS,
391 DBUS_INTERFACE_DBUS,
392 "RequestName")))
393 return -ENOMEM;
394
395 if (!dbus_message_append_args(
396 message,
397 DBUS_TYPE_STRING, &name,
398 DBUS_TYPE_UINT32, &flags,
399 DBUS_TYPE_INVALID)) {
400 dbus_message_unref(message);
401 return -ENOMEM;
402 }
403
404 if (!dbus_connection_send(m->bus, message, NULL)) {
405 dbus_message_unref(message);
406 return -ENOMEM;
407 }
408
409 /* We simple ask for the name and don't wait for it. Sooner or
410 * later we'll have it, and we wouldn't know what to do on
411 * error anyway. */
412
413 dbus_message_unref(message);
414
415 return 0;
416 }
417
418 static int bus_setup_loop(Manager *m, DBusConnection *bus) {
419 assert(m);
420 assert(bus);
421
422 dbus_connection_set_exit_on_disconnect(bus, FALSE);
423 if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
424 !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
425 return -ENOMEM;
426
427 return 0;
428 }
429
430 int bus_init(Manager *m) {
431 DBusError error;
432 char *id;
433 int r;
434
435 assert(m);
436
437 if (m->bus)
438 return 0;
439
440 if (!(m->subscribed = set_new(string_hash_func, string_compare_func)))
441 return -ENOMEM;
442
443 dbus_connection_set_change_sigpipe(FALSE);
444
445 dbus_error_init(&error);
446 if (!(m->bus = dbus_bus_get_private(m->running_as == MANAGER_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
447 log_error("Failed to get D-Bus connection: %s", error.message);
448 dbus_error_free(&error);
449 bus_done(m);
450 return -ECONNREFUSED;
451 }
452
453 if ((r = bus_setup_loop(m, m->bus)) < 0) {
454 bus_done(m);
455 return r;
456 }
457
458 dbus_connection_set_dispatch_status_function(m->bus, bus_dispatch_status, m, NULL);
459
460 if (m->running_as == MANAGER_SESSION) {
461 if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
462 log_error("Failed to get D-Bus connection: %s", error.message);
463 dbus_error_free(&error);
464 bus_done(m);
465 return -ECONNREFUSED;
466 }
467
468 if ((r = bus_setup_loop(m, m->system_bus)) < 0) {
469 bus_done(m);
470 return r;
471 }
472
473 dbus_connection_set_dispatch_status_function(m->system_bus, system_bus_dispatch_status, m, NULL);
474 } else
475 m->system_bus = m->bus;
476
477 if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
478 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
479 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
480 !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL) ||
481 !dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
482 bus_done(m);
483 return -ENOMEM;
484 }
485
486 dbus_bus_add_match(m->bus,
487 "type='signal',"
488 "sender='"DBUS_SERVICE_DBUS"',"
489 "interface='"DBUS_INTERFACE_DBUS"',"
490 "path='"DBUS_PATH_DBUS"'",
491 &error);
492
493 if (dbus_error_is_set(&error)) {
494 log_error("Failed to register match: %s", error.message);
495 dbus_error_free(&error);
496 return -ENOMEM;
497 }
498
499 if ((r = request_name(m)) < 0) {
500 bus_done(m);
501 return r;
502 }
503
504 dbus_bus_add_match(m->system_bus,
505 "type='signal',"
506 "interface='org.freedesktop.systemd1.Agent',"
507 "path='/org/freedesktop/systemd1/agent'",
508 &error);
509
510 if (dbus_error_is_set(&error)) {
511 log_error("Failed to register match: %s", error.message);
512 dbus_error_free(&error);
513 bus_done(m);
514 return -ENOMEM;
515 }
516
517 log_debug("Successfully connected to D-Bus bus %s as %s",
518 strnull((id = dbus_connection_get_server_id(m->bus))),
519 strnull(dbus_bus_get_unique_name(m->bus)));
520 dbus_free(id);
521
522 log_debug("Successfully connected to system D-Bus bus %s as %s",
523 strnull((id = dbus_connection_get_server_id(m->system_bus))),
524 strnull(dbus_bus_get_unique_name(m->system_bus)));
525 dbus_free(id);
526
527 m->request_bus_dispatch = true;
528 m->request_system_bus_dispatch = true;
529
530 return 0;
531 }
532
533 void bus_done(Manager *m) {
534 assert(m);
535
536 if (m->system_bus && m->system_bus != m->bus) {
537 dbus_connection_close(m->system_bus);
538 dbus_connection_unref(m->system_bus);
539 m->system_bus = NULL;
540 }
541
542 if (m->bus) {
543 dbus_connection_close(m->bus);
544 dbus_connection_unref(m->bus);
545 m->bus = NULL;
546 }
547
548 if (m->subscribed) {
549 char *c;
550
551 while ((c = set_steal_first(m->subscribed)))
552 free(c);
553
554 set_free(m->subscribed);
555 m->subscribed = NULL;
556 }
557 }
558
559 DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
560 DBusError error;
561 DBusMessage *reply = NULL;
562 int r;
563
564 assert(m);
565 assert(message);
566
567 dbus_error_init(&error);
568
569 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
570
571 if (!(reply = dbus_message_new_method_return(message)))
572 goto oom;
573
574 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
575 goto oom;
576
577 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) {
578 const char *interface, *property;
579 const BusProperty *p;
580
581 if (!dbus_message_get_args(
582 message,
583 &error,
584 DBUS_TYPE_STRING, &interface,
585 DBUS_TYPE_STRING, &property,
586 DBUS_TYPE_INVALID))
587 return bus_send_error_reply(m, message, &error, -EINVAL);
588
589 for (p = properties; p->property; p++)
590 if (streq(p->interface, interface) && streq(p->property, property))
591 break;
592
593 if (p->property) {
594 DBusMessageIter iter, sub;
595
596 if (!(reply = dbus_message_new_method_return(message)))
597 goto oom;
598
599 dbus_message_iter_init_append(reply, &iter);
600
601 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
602 goto oom;
603
604 if ((r = p->append(m, &sub, property, p->data)) < 0) {
605
606 if (r == -ENOMEM)
607 goto oom;
608
609 dbus_message_unref(reply);
610 return bus_send_error_reply(m, message, NULL, r);
611 }
612
613 if (!dbus_message_iter_close_container(&iter, &sub))
614 goto oom;
615 }
616 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
617 const char *interface;
618 const BusProperty *p;
619 DBusMessageIter iter, sub, sub2, sub3;
620 bool any = false;
621
622 if (!dbus_message_get_args(
623 message,
624 &error,
625 DBUS_TYPE_STRING, &interface,
626 DBUS_TYPE_INVALID))
627 return bus_send_error_reply(m, message, &error, -EINVAL);
628
629 if (!(reply = dbus_message_new_method_return(message)))
630 goto oom;
631
632 dbus_message_iter_init_append(reply, &iter);
633
634 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
635 goto oom;
636
637 for (p = properties; p->property; p++) {
638 if (!streq(p->interface, interface))
639 continue;
640
641 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
642 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
643 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
644 goto oom;
645
646 if ((r = p->append(m, &sub3, p->property, p->data)) < 0) {
647
648 if (r == -ENOMEM)
649 goto oom;
650
651 dbus_message_unref(reply);
652 return bus_send_error_reply(m, message, NULL, r);
653 }
654
655 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
656 !dbus_message_iter_close_container(&sub, &sub2))
657 goto oom;
658
659 any = true;
660 }
661
662 if (!dbus_message_iter_close_container(&iter, &sub))
663 goto oom;
664 }
665
666 if (reply) {
667 if (!dbus_connection_send(m->bus, reply, NULL))
668 goto oom;
669
670 dbus_message_unref(reply);
671 return DBUS_HANDLER_RESULT_HANDLED;
672 }
673
674 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
675
676 oom:
677 if (reply)
678 dbus_message_unref(reply);
679
680 dbus_error_free(&error);
681
682 return DBUS_HANDLER_RESULT_NEED_MEMORY;
683 }
684
685 static const char *error_to_dbus(int error) {
686
687 switch(error) {
688
689 case -EINVAL:
690 return DBUS_ERROR_INVALID_ARGS;
691
692 case -ENOMEM:
693 return DBUS_ERROR_NO_MEMORY;
694
695 case -EPERM:
696 case -EACCES:
697 return DBUS_ERROR_ACCESS_DENIED;
698
699 case -ESRCH:
700 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
701
702 case -ENOENT:
703 return DBUS_ERROR_FILE_NOT_FOUND;
704
705 case -EEXIST:
706 return DBUS_ERROR_FILE_EXISTS;
707
708 case -ETIMEDOUT:
709 return DBUS_ERROR_TIMEOUT;
710
711 case -EIO:
712 return DBUS_ERROR_IO_ERROR;
713
714 case -ENETRESET:
715 case -ECONNABORTED:
716 case -ECONNRESET:
717 return DBUS_ERROR_DISCONNECTED;
718 }
719
720 return DBUS_ERROR_FAILED;
721 }
722
723 DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error) {
724 DBusMessage *reply = NULL;
725 const char *name, *text;
726
727 if (bus_error && dbus_error_is_set(bus_error)) {
728 name = bus_error->name;
729 text = bus_error->message;
730 } else {
731 name = error_to_dbus(error);
732 text = strerror(-error);
733 }
734
735 if (!(reply = dbus_message_new_error(message, name, text)))
736 goto oom;
737
738 if (!dbus_connection_send(m->bus, reply, NULL))
739 goto oom;
740
741 dbus_message_unref(reply);
742
743 if (bus_error)
744 dbus_error_free(bus_error);
745
746 return DBUS_HANDLER_RESULT_HANDLED;
747
748 oom:
749 if (reply)
750 dbus_message_unref(reply);
751
752 if (bus_error)
753 dbus_error_free(bus_error);
754
755 return DBUS_HANDLER_RESULT_NEED_MEMORY;
756 }
757
758 int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) {
759 const char *t = data;
760
761 assert(m);
762 assert(i);
763 assert(property);
764
765 if (!t)
766 t = "";
767
768 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
769 return -ENOMEM;
770
771 return 0;
772 }
773
774 int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) {
775 DBusMessageIter sub;
776 char **t = data;
777
778 assert(m);
779 assert(i);
780 assert(property);
781
782 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
783 return -ENOMEM;
784
785 STRV_FOREACH(t, t)
786 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
787 return -ENOMEM;
788
789 if (!dbus_message_iter_close_container(i, &sub))
790 return -ENOMEM;
791
792 return 0;
793 }
794
795 int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) {
796 bool *b = data;
797 dbus_bool_t db;
798
799 assert(m);
800 assert(i);
801 assert(property);
802 assert(b);
803
804 db = *b;
805
806 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
807 return -ENOMEM;
808
809 return 0;
810 }
811
812 int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) {
813 assert(m);
814 assert(i);
815 assert(property);
816 assert(data);
817
818 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
819 return -ENOMEM;
820
821 return 0;
822 }
823
824 int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
825 assert(m);
826 assert(i);
827 assert(property);
828 assert(data);
829
830 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
831 return -ENOMEM;
832
833 return 0;
834 }