dbus: minor coding style fixes
[systemd_ALT/systemd_imz.git] / src / shared / dbus-common.c
blobbcbef77b53411d2739874145b275d38470f62c56
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3 /***
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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 ***/
22 #include <assert.h>
23 #include <sys/socket.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <dbus/dbus.h>
29 #include <string.h>
30 #include <sys/epoll.h>
32 #include "log.h"
33 #include "dbus-common.h"
34 #include "util.h"
35 #include "def.h"
36 #include "strv.h"
38 int bus_check_peercred(DBusConnection *c) {
39 int fd;
40 struct ucred ucred;
41 socklen_t l;
43 assert(c);
45 assert_se(dbus_connection_get_unix_fd(c, &fd));
47 l = sizeof(struct ucred);
48 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
49 log_error("SO_PEERCRED failed: %m");
50 return -errno;
53 if (l != sizeof(struct ucred)) {
54 log_error("SO_PEERCRED returned wrong size.");
55 return -E2BIG;
58 if (ucred.uid != 0 && ucred.uid != geteuid())
59 return -EPERM;
61 return 1;
64 static int sync_auth(DBusConnection *bus, DBusError *error) {
65 usec_t begin, tstamp;
67 assert(bus);
69 /* This complexity should probably move into D-Bus itself:
71 * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
73 begin = tstamp = now(CLOCK_MONOTONIC);
74 for (;;) {
76 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
77 break;
79 if (dbus_connection_get_is_authenticated(bus))
80 break;
82 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
83 break;
85 tstamp = now(CLOCK_MONOTONIC);
88 if (!dbus_connection_get_is_connected(bus)) {
89 dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
90 return -ECONNREFUSED;
93 if (!dbus_connection_get_is_authenticated(bus)) {
94 dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
95 return -EACCES;
98 return 0;
101 int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
102 DBusConnection *bus = NULL;
103 int r;
104 bool private = true;
106 assert(_bus);
108 if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
109 /* If we are root, then let's talk directly to the
110 * system instance, instead of going via the bus */
112 bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
113 if (!bus)
114 return -EIO;
116 } else {
117 if (t == DBUS_BUS_SESSION) {
118 const char *e;
120 /* If we are supposed to talk to the instance,
121 * try via XDG_RUNTIME_DIR first, then
122 * fallback to normal bus access */
124 e = __secure_getenv("XDG_RUNTIME_DIR");
125 if (e) {
126 char *p;
128 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
129 return -ENOMEM;
131 bus = dbus_connection_open_private(p, NULL);
132 free(p);
136 if (!bus) {
137 bus = dbus_bus_get_private(t, error);
138 if (!bus)
139 return -EIO;
141 private = false;
145 dbus_connection_set_exit_on_disconnect(bus, FALSE);
147 if (private) {
148 if (bus_check_peercred(bus) < 0) {
149 dbus_connection_close(bus);
150 dbus_connection_unref(bus);
152 dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
153 return -EACCES;
157 r = sync_auth(bus, error);
158 if (r < 0) {
159 dbus_connection_close(bus);
160 dbus_connection_unref(bus);
161 return r;
164 if (_private)
165 *_private = private;
167 *_bus = bus;
168 return 0;
171 int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
172 DBusConnection *bus;
173 char *p = NULL;
174 int r;
176 assert(_bus);
177 assert(user || host);
179 if (user && host)
180 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
181 else if (user)
182 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
183 else if (host)
184 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
186 if (!p) {
187 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
188 return -ENOMEM;
191 bus = dbus_connection_open_private(p, error);
192 free(p);
194 if (!bus)
195 return -EIO;
197 dbus_connection_set_exit_on_disconnect(bus, FALSE);
199 if ((r = sync_auth(bus, error)) < 0) {
200 dbus_connection_close(bus);
201 dbus_connection_unref(bus);
202 return r;
205 if (!dbus_bus_register(bus, error)) {
206 dbus_connection_close(bus);
207 dbus_connection_unref(bus);
208 return r;
211 *_bus = bus;
212 return 0;
215 int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
216 DBusConnection *bus;
217 int r;
219 assert(_bus);
221 /* Don't bother with PolicyKit if we are root */
222 if (geteuid() == 0)
223 return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
225 bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
226 if (!bus)
227 return -EIO;
229 dbus_connection_set_exit_on_disconnect(bus, FALSE);
231 if ((r = sync_auth(bus, error)) < 0) {
232 dbus_connection_close(bus);
233 dbus_connection_unref(bus);
234 return r;
237 if (!dbus_bus_register(bus, error)) {
238 dbus_connection_close(bus);
239 dbus_connection_unref(bus);
240 return r;
243 *_bus = bus;
244 return 0;
247 const char *bus_error_message(const DBusError *error) {
248 if (!error)
249 return NULL;
251 /* Sometimes the D-Bus server is a little bit too verbose with
252 * its error messages, so let's override them here */
253 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
254 return "Access denied";
256 return error->message;
259 const char *bus_error_message_or_strerror(const DBusError *error, int err) {
261 if (error && dbus_error_is_set(error))
262 return bus_error_message(error);
264 return strerror(err);
267 DBusHandlerResult bus_default_message_handler(
268 DBusConnection *c,
269 DBusMessage *message,
270 const char *introspection,
271 const char *interfaces,
272 const BusBoundProperties *bound_properties) {
274 DBusError error;
275 DBusMessage *reply = NULL;
276 int r;
278 assert(c);
279 assert(message);
281 dbus_error_init(&error);
283 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
285 if (!(reply = dbus_message_new_method_return(message)))
286 goto oom;
288 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
289 goto oom;
291 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
292 const char *interface, *property;
293 const BusBoundProperties *bp;
294 const BusProperty *p;
295 void *data;
296 DBusMessageIter iter, sub;
298 if (!dbus_message_get_args(
299 message,
300 &error,
301 DBUS_TYPE_STRING, &interface,
302 DBUS_TYPE_STRING, &property,
303 DBUS_TYPE_INVALID))
304 return bus_send_error_reply(c, message, &error, -EINVAL);
306 for (bp = bound_properties; bp->interface; bp++) {
307 if (!streq(bp->interface, interface))
308 continue;
310 for (p = bp->properties; p->property; p++)
311 if (streq(p->property, property))
312 goto get_prop;
315 /* no match */
316 if (!nulstr_contains(interfaces, interface))
317 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
318 else
319 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
321 return bus_send_error_reply(c, message, &error, -EINVAL);
323 get_prop:
324 reply = dbus_message_new_method_return(message);
325 if (!reply)
326 goto oom;
328 dbus_message_iter_init_append(reply, &iter);
330 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
331 goto oom;
333 data = (char*)bp->base + p->offset;
334 if (p->indirect)
335 data = *(void**)data;
336 r = p->append(&sub, property, data);
337 if (r < 0) {
338 if (r == -ENOMEM)
339 goto oom;
341 dbus_message_unref(reply);
342 return bus_send_error_reply(c, message, NULL, r);
345 if (!dbus_message_iter_close_container(&iter, &sub))
346 goto oom;
348 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
349 const char *interface;
350 const BusBoundProperties *bp;
351 const BusProperty *p;
352 DBusMessageIter iter, sub, sub2, sub3;
354 if (!dbus_message_get_args(
355 message,
356 &error,
357 DBUS_TYPE_STRING, &interface,
358 DBUS_TYPE_INVALID))
359 return bus_send_error_reply(c, message, &error, -EINVAL);
361 if (interface[0] && !nulstr_contains(interfaces, interface)) {
362 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
363 return bus_send_error_reply(c, message, &error, -EINVAL);
366 if (!(reply = dbus_message_new_method_return(message)))
367 goto oom;
369 dbus_message_iter_init_append(reply, &iter);
371 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
372 goto oom;
374 for (bp = bound_properties; bp->interface; bp++) {
375 if (interface[0] && !streq(bp->interface, interface))
376 continue;
378 for (p = bp->properties; p->property; p++) {
379 void *data;
381 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
382 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
383 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
384 goto oom;
386 data = (char*)bp->base + p->offset;
387 if (p->indirect)
388 data = *(void**)data;
389 r = p->append(&sub3, p->property, data);
390 if (r < 0) {
391 if (r == -ENOMEM)
392 goto oom;
394 dbus_message_unref(reply);
395 return bus_send_error_reply(c, message, NULL, r);
398 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
399 !dbus_message_iter_close_container(&sub, &sub2))
400 goto oom;
404 if (!dbus_message_iter_close_container(&iter, &sub))
405 goto oom;
407 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
408 const char *interface, *property;
409 DBusMessageIter iter;
410 const BusBoundProperties *bp;
411 const BusProperty *p;
412 DBusMessageIter sub;
413 char *sig;
414 void *data;
415 DBusMessage *changed;
417 if (!dbus_message_iter_init(message, &iter) ||
418 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
419 return bus_send_error_reply(c, message, NULL, -EINVAL);
421 dbus_message_iter_get_basic(&iter, &interface);
423 if (!dbus_message_iter_next(&iter) ||
424 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
425 return bus_send_error_reply(c, message, NULL, -EINVAL);
427 dbus_message_iter_get_basic(&iter, &property);
429 if (!dbus_message_iter_next(&iter) ||
430 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
431 dbus_message_iter_has_next(&iter))
432 return bus_send_error_reply(c, message, NULL, -EINVAL);
434 for (bp = bound_properties; bp->interface; bp++) {
435 if (!streq(bp->interface, interface))
436 continue;
438 for (p = bp->properties; p->property; p++)
439 if (streq(p->property, property))
440 goto set_prop;
443 /* no match */
444 if (!nulstr_contains(interfaces, interface))
445 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
446 else
447 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
449 return bus_send_error_reply(c, message, &error, -EINVAL);
451 set_prop:
452 if (!p->set) {
453 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
454 return bus_send_error_reply(c, message, &error, -EINVAL);
457 dbus_message_iter_recurse(&iter, &sub);
459 sig = dbus_message_iter_get_signature(&sub);
460 if (!sig)
461 goto oom;
463 if (!streq(sig, p->signature)) {
464 dbus_free(sig);
465 return bus_send_error_reply(c, message, NULL, -EINVAL);
467 dbus_free(sig);
469 data = (uint8_t*) bp->base + p->offset;
470 if (p->indirect)
471 data = *(void**)data;
473 r = p->set(&sub, property, data);
474 if (r == -ENOMEM)
475 goto oom;
476 else if (r < 0)
477 return bus_send_error_reply(c, message, NULL, r);
479 reply = dbus_message_new_method_return(message);
480 if (!reply)
481 goto oom;
483 /* Send out a signal about this, but it doesn't really
484 * matter if this fails, so eat all errors */
485 changed = bus_properties_changed_one_new(
486 dbus_message_get_path(message),
487 interface,
488 property);
489 if (changed) {
490 dbus_connection_send(c, changed, NULL);
491 dbus_message_unref(changed);
495 } else {
496 const char *interface = dbus_message_get_interface(message);
498 if (!interface || !nulstr_contains(interfaces, interface)) {
499 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
500 return bus_send_error_reply(c, message, &error, -EINVAL);
504 if (reply) {
505 if (!dbus_connection_send(c, reply, NULL))
506 goto oom;
508 dbus_message_unref(reply);
509 return DBUS_HANDLER_RESULT_HANDLED;
512 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
514 oom:
515 if (reply)
516 dbus_message_unref(reply);
518 dbus_error_free(&error);
520 return DBUS_HANDLER_RESULT_NEED_MEMORY;
523 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
524 const char *t = data;
526 assert(i);
527 assert(property);
529 if (!t)
530 t = "";
532 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
533 return -ENOMEM;
535 return 0;
538 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
539 char **t = data;
541 assert(i);
542 assert(property);
544 return bus_append_strv_iter(i, t);
547 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
548 bool *b = data;
549 dbus_bool_t db;
551 assert(i);
552 assert(property);
553 assert(b);
555 db = *b;
557 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
558 return -ENOMEM;
560 return 0;
563 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
564 int *b = data;
565 dbus_bool_t db;
567 assert(i);
568 assert(property);
569 assert(b);
571 db = *b > 0;
573 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
574 return -ENOMEM;
576 return 0;
579 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
580 assert(i);
581 assert(property);
582 assert(data);
584 /* Let's ensure that usec_t is actually 64bit, and hence this
585 * function can be used for usec_t */
586 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
588 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
589 return -ENOMEM;
591 return 0;
594 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
595 assert(i);
596 assert(property);
597 assert(data);
599 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
600 * 32bit, and hence this function can be used for
601 * pid_t/mode_t/uid_t/gid_t */
602 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
603 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
604 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
605 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
606 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
608 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
609 return -ENOMEM;
611 return 0;
614 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
615 assert(i);
616 assert(property);
617 assert(data);
619 assert_cc(sizeof(int32_t) == sizeof(int));
621 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
622 return -ENOMEM;
624 return 0;
627 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
628 uint64_t u;
630 assert(i);
631 assert(property);
632 assert(data);
634 u = (uint64_t) *(size_t*) data;
636 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
637 return -ENOMEM;
639 return 0;
642 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
643 uint64_t u;
645 assert(i);
646 assert(property);
647 assert(data);
649 u = (uint64_t) *(unsigned long*) data;
651 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
652 return -ENOMEM;
654 return 0;
657 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
658 int64_t l;
660 assert(i);
661 assert(property);
662 assert(data);
664 l = (int64_t) *(long*) data;
666 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
667 return -ENOMEM;
669 return 0;
672 int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
673 uint64_t *t = data;
675 assert(i);
676 assert(property);
678 dbus_message_iter_get_basic(i, t);
679 return 0;
682 const char *bus_errno_to_dbus(int error) {
684 switch(error) {
686 case -EINVAL:
687 return DBUS_ERROR_INVALID_ARGS;
689 case -ENOMEM:
690 return DBUS_ERROR_NO_MEMORY;
692 case -EPERM:
693 case -EACCES:
694 return DBUS_ERROR_ACCESS_DENIED;
696 case -ESRCH:
697 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
699 case -ENOENT:
700 return DBUS_ERROR_FILE_NOT_FOUND;
702 case -EEXIST:
703 return DBUS_ERROR_FILE_EXISTS;
705 case -ETIMEDOUT:
706 case -ETIME:
707 return DBUS_ERROR_TIMEOUT;
709 case -EIO:
710 return DBUS_ERROR_IO_ERROR;
712 case -ENETRESET:
713 case -ECONNABORTED:
714 case -ECONNRESET:
715 return DBUS_ERROR_DISCONNECTED;
718 return DBUS_ERROR_FAILED;
721 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
722 DBusMessage *reply = NULL;
723 const char *name, *text;
725 if (berror && dbus_error_is_set(berror)) {
726 name = berror->name;
727 text = berror->message;
728 } else {
729 name = bus_errno_to_dbus(error);
730 text = strerror(-error);
733 if (!(reply = dbus_message_new_error(message, name, text)))
734 goto oom;
736 if (!dbus_connection_send(c, reply, NULL))
737 goto oom;
739 dbus_message_unref(reply);
741 if (berror)
742 dbus_error_free(berror);
744 return DBUS_HANDLER_RESULT_HANDLED;
746 oom:
747 if (reply)
748 dbus_message_unref(reply);
750 if (berror)
751 dbus_error_free(berror);
753 return DBUS_HANDLER_RESULT_NEED_MEMORY;
756 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
757 DBusMessage *m;
758 DBusMessageIter iter, sub;
759 const char *i;
761 assert(interface);
762 assert(properties);
764 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
765 if (!m)
766 goto oom;
768 dbus_message_iter_init_append(m, &iter);
770 /* We won't send any property values, since they might be
771 * large and sometimes not cheap to generated */
773 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
774 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
775 !dbus_message_iter_close_container(&iter, &sub) ||
776 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
777 goto oom;
779 NULSTR_FOREACH(i, properties)
780 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
781 goto oom;
783 if (!dbus_message_iter_close_container(&iter, &sub))
784 goto oom;
786 return m;
788 oom:
789 if (m)
790 dbus_message_unref(m);
792 return NULL;
795 DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
796 DBusMessage *m;
797 DBusMessageIter iter, sub;
799 assert(interface);
800 assert(property);
802 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
803 if (!m)
804 goto oom;
806 dbus_message_iter_init_append(m, &iter);
808 /* We won't send any property values, since they might be
809 * large and sometimes not cheap to generated */
811 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
812 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
813 !dbus_message_iter_close_container(&iter, &sub) ||
814 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
815 goto oom;
817 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
818 goto oom;
820 if (!dbus_message_iter_close_container(&iter, &sub))
821 goto oom;
823 return m;
825 oom:
826 if (m)
827 dbus_message_unref(m);
829 return NULL;
832 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
833 unsigned flags;
834 uint32_t events = 0;
836 assert(bus_watch);
838 /* no watch flags for disabled watches */
839 if (!dbus_watch_get_enabled(bus_watch))
840 return 0;
842 flags = dbus_watch_get_flags(bus_watch);
844 if (flags & DBUS_WATCH_READABLE)
845 events |= EPOLLIN;
846 if (flags & DBUS_WATCH_WRITABLE)
847 events |= EPOLLOUT;
849 return events | EPOLLHUP | EPOLLERR;
852 unsigned bus_events_to_flags(uint32_t events) {
853 unsigned flags = 0;
855 if (events & EPOLLIN)
856 flags |= DBUS_WATCH_READABLE;
857 if (events & EPOLLOUT)
858 flags |= DBUS_WATCH_WRITABLE;
859 if (events & EPOLLHUP)
860 flags |= DBUS_WATCH_HANGUP;
861 if (events & EPOLLERR)
862 flags |= DBUS_WATCH_ERROR;
864 return flags;
867 int bus_parse_strv(DBusMessage *m, char ***_l) {
868 DBusMessageIter iter;
870 assert(m);
871 assert(_l);
873 if (!dbus_message_iter_init(m, &iter))
874 return -EINVAL;
876 return bus_parse_strv_iter(&iter, _l);
879 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
880 DBusMessageIter sub;
881 unsigned n = 0, i = 0;
882 char **l;
884 assert(iter);
885 assert(_l);
887 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
888 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
889 return -EINVAL;
891 dbus_message_iter_recurse(iter, &sub);
893 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
894 n++;
895 dbus_message_iter_next(&sub);
898 if (!(l = new(char*, n+1)))
899 return -ENOMEM;
901 dbus_message_iter_recurse(iter, &sub);
903 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
904 const char *s;
906 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
907 dbus_message_iter_get_basic(&sub, &s);
909 if (!(l[i++] = strdup(s))) {
910 strv_free(l);
911 return -ENOMEM;
914 dbus_message_iter_next(&sub);
917 assert(i == n);
918 l[i] = NULL;
920 if (_l)
921 *_l = l;
923 return 0;
926 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
927 DBusMessageIter sub;
929 assert(iter);
931 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
932 return -ENOMEM;
934 STRV_FOREACH(l, l)
935 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
936 return -ENOMEM;
938 if (!dbus_message_iter_close_container(iter, &sub))
939 return -ENOMEM;
941 return 0;
944 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
946 assert(iter);
947 assert(data);
949 if (dbus_message_iter_get_arg_type(iter) != type)
950 return -EIO;
952 dbus_message_iter_get_basic(iter, data);
954 if (!dbus_message_iter_next(iter) != !next)
955 return -EIO;
957 return 0;
960 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
961 assert(name);
962 assert(iter);
964 switch (dbus_message_iter_get_arg_type(iter)) {
966 case DBUS_TYPE_STRING: {
967 const char *s;
968 dbus_message_iter_get_basic(iter, &s);
970 if (all || !isempty(s))
971 printf("%s=%s\n", name, s);
973 return 1;
976 case DBUS_TYPE_BOOLEAN: {
977 dbus_bool_t b;
979 dbus_message_iter_get_basic(iter, &b);
980 printf("%s=%s\n", name, yes_no(b));
982 return 1;
985 case DBUS_TYPE_UINT64: {
986 uint64_t u;
987 dbus_message_iter_get_basic(iter, &u);
989 /* Yes, heuristics! But we can change this check
990 * should it turn out to not be sufficient */
992 if (endswith(name, "Timestamp")) {
993 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
995 t = format_timestamp(timestamp, sizeof(timestamp), u);
996 if (t || all)
997 printf("%s=%s\n", name, strempty(t));
999 } else if (strstr(name, "USec")) {
1000 char timespan[FORMAT_TIMESPAN_MAX];
1002 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1003 } else
1004 printf("%s=%llu\n", name, (unsigned long long) u);
1006 return 1;
1009 case DBUS_TYPE_UINT32: {
1010 uint32_t u;
1011 dbus_message_iter_get_basic(iter, &u);
1013 if (strstr(name, "UMask") || strstr(name, "Mode"))
1014 printf("%s=%04o\n", name, u);
1015 else
1016 printf("%s=%u\n", name, (unsigned) u);
1018 return 1;
1021 case DBUS_TYPE_INT32: {
1022 int32_t i;
1023 dbus_message_iter_get_basic(iter, &i);
1025 printf("%s=%i\n", name, (int) i);
1026 return 1;
1029 case DBUS_TYPE_DOUBLE: {
1030 double d;
1031 dbus_message_iter_get_basic(iter, &d);
1033 printf("%s=%g\n", name, d);
1034 return 1;
1037 case DBUS_TYPE_ARRAY:
1039 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1040 DBusMessageIter sub;
1041 bool space = false;
1043 dbus_message_iter_recurse(iter, &sub);
1044 if (all ||
1045 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1046 printf("%s=", name);
1048 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1049 const char *s;
1051 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1052 dbus_message_iter_get_basic(&sub, &s);
1053 printf("%s%s", space ? " " : "", s);
1055 space = true;
1056 dbus_message_iter_next(&sub);
1059 puts("");
1062 return 1;
1064 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1065 DBusMessageIter sub;
1067 dbus_message_iter_recurse(iter, &sub);
1068 if (all ||
1069 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1070 printf("%s=", name);
1072 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1073 uint8_t u;
1075 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1076 dbus_message_iter_get_basic(&sub, &u);
1077 printf("%02x", u);
1079 dbus_message_iter_next(&sub);
1082 puts("");
1085 return 1;
1087 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1088 DBusMessageIter sub;
1090 dbus_message_iter_recurse(iter, &sub);
1091 if (all ||
1092 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1093 printf("%s=", name);
1095 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1096 uint32_t u;
1098 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1099 dbus_message_iter_get_basic(&sub, &u);
1100 printf("%08x", u);
1102 dbus_message_iter_next(&sub);
1105 puts("");
1108 return 1;
1111 break;
1114 return 0;
1117 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1118 DBusMessage *reply;
1119 DBusConnection *bus = userdata;
1121 assert_se(reply = dbus_pending_call_steal_reply(pending));
1122 dbus_message_unref(reply);
1124 dbus_connection_close(bus);
1127 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1128 DBusMessage *m = NULL;
1129 DBusPendingCall *pending = NULL;
1131 assert(bus);
1133 /* We unregister the name here, but we continue to process
1134 * requests, until we get the response for it, so that all
1135 * requests are guaranteed to be processed. */
1137 m = dbus_message_new_method_call(
1138 DBUS_SERVICE_DBUS,
1139 DBUS_PATH_DBUS,
1140 DBUS_INTERFACE_DBUS,
1141 "ReleaseName");
1142 if (!m)
1143 goto oom;
1145 if (!dbus_message_append_args(
1147 DBUS_TYPE_STRING,
1148 &name,
1149 DBUS_TYPE_INVALID))
1150 goto oom;
1152 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1153 goto oom;
1155 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1156 goto oom;
1158 dbus_message_unref(m);
1159 dbus_pending_call_unref(pending);
1161 return;
1163 oom:
1164 log_oom();
1166 if (pending) {
1167 dbus_pending_call_cancel(pending);
1168 dbus_pending_call_unref(pending);
1171 if (m)
1172 dbus_message_unref(m);
1175 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1176 usec_t *remain_until = userdata;
1178 assert(bus);
1179 assert(m);
1180 assert(remain_until);
1182 /* Every time we get a new message we reset out timeout */
1183 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1185 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1186 dbus_connection_close(bus);
1188 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1191 /* This mimics dbus_bus_get_unix_user() */
1192 pid_t bus_get_unix_process_id(
1193 DBusConnection *connection,
1194 const char *name,
1195 DBusError *error) {
1197 DBusMessage *m = NULL, *reply = NULL;
1198 uint32_t pid = 0;
1200 m = dbus_message_new_method_call(
1201 DBUS_SERVICE_DBUS,
1202 DBUS_PATH_DBUS,
1203 DBUS_INTERFACE_DBUS,
1204 "GetConnectionUnixProcessID");
1205 if (!m) {
1206 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1207 goto finish;
1210 if (!dbus_message_append_args(
1212 DBUS_TYPE_STRING, &name,
1213 DBUS_TYPE_INVALID)) {
1214 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1215 goto finish;
1218 reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1219 if (!reply)
1220 goto finish;
1222 if (dbus_set_error_from_message(error, reply))
1223 goto finish;
1225 if (!dbus_message_get_args(
1226 reply, error,
1227 DBUS_TYPE_UINT32, &pid,
1228 DBUS_TYPE_INVALID))
1229 goto finish;
1231 finish:
1232 if (m)
1233 dbus_message_unref(m);
1235 if (reply)
1236 dbus_message_unref(reply);
1238 return (pid_t) pid;
1241 bool bus_error_is_no_service(const DBusError *error) {
1242 assert(error);
1244 if (!dbus_error_is_set(error))
1245 return false;
1247 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
1248 return true;
1250 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
1251 return true;
1253 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
1256 int bus_method_call_with_reply(DBusConnection *bus,
1257 const char *destination,
1258 const char *path,
1259 const char *interface,
1260 const char *method,
1261 DBusMessage **return_reply,
1262 DBusError *return_error,
1263 int first_arg_type, ...) {
1264 DBusError error;
1265 DBusMessage *m, *reply;
1266 va_list ap;
1267 int r = 0;
1269 dbus_error_init(&error);
1270 assert(bus);
1272 m = dbus_message_new_method_call(destination, path, interface, method);
1273 if (!m) {
1274 r = log_oom();
1275 goto finish;
1278 va_start(ap, first_arg_type);
1279 if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
1280 va_end(ap);
1281 r = log_oom();
1282 goto finish;
1284 va_end(ap);
1286 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1287 if (!reply) {
1288 if (!return_error)
1289 log_error("Failed to issue method call: %s", bus_error_message(&error));
1290 if (bus_error_is_no_service(&error))
1291 r = -ENOENT;
1292 else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
1293 r = -EACCES;
1294 else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
1295 r = -ETIMEDOUT;
1296 else
1297 r = -EIO;
1298 goto finish;
1301 if (return_reply)
1302 *return_reply = reply;
1303 else
1304 dbus_message_unref(reply);
1306 finish:
1307 if (m)
1308 dbus_message_unref(m);
1310 if (return_error)
1311 *return_error = error;
1312 else
1313 dbus_error_free(&error);
1315 return r;