]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/dbus-common.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / dbus-common.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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 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 <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>
31
32 #include "log.h"
33 #include "dbus-common.h"
34 #include "util.h"
35 #include "def.h"
36 #include "strv.h"
37
38 int bus_check_peercred(DBusConnection *c) {
39 int fd;
40 struct ucred ucred;
41 socklen_t l;
42
43 assert(c);
44
45 assert_se(dbus_connection_get_unix_fd(c, &fd));
46
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;
51 }
52
53 if (l != sizeof(struct ucred)) {
54 log_error("SO_PEERCRED returned wrong size.");
55 return -E2BIG;
56 }
57
58 if (ucred.uid != 0 && ucred.uid != geteuid())
59 return -EPERM;
60
61 return 1;
62 }
63
64 static int sync_auth(DBusConnection *bus, DBusError *error) {
65 usec_t begin, tstamp;
66
67 assert(bus);
68
69 /* This complexity should probably move into D-Bus itself:
70 *
71 * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
72
73 begin = tstamp = now(CLOCK_MONOTONIC);
74 for (;;) {
75
76 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
77 break;
78
79 if (dbus_connection_get_is_authenticated(bus))
80 break;
81
82 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
83 break;
84
85 tstamp = now(CLOCK_MONOTONIC);
86 }
87
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;
91 }
92
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;
96 }
97
98 return 0;
99 }
100
101 int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
102 DBusConnection *bus = NULL;
103 int r;
104 bool private = true;
105
106 assert(_bus);
107
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 */
111
112 bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
113 if (!bus)
114 return -EIO;
115
116 } else {
117 if (t == DBUS_BUS_SESSION) {
118 const char *e;
119
120 /* If we are supposed to talk to the instance,
121 * try via XDG_RUNTIME_DIR first, then
122 * fallback to normal bus access */
123
124 e = getenv("XDG_RUNTIME_DIR");
125 if (e) {
126 char *p;
127
128 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
129 return -ENOMEM;
130
131 bus = dbus_connection_open_private(p, NULL);
132 free(p);
133 }
134 }
135
136 if (!bus) {
137 bus = dbus_bus_get_private(t, error);
138 if (!bus)
139 return -EIO;
140
141 private = false;
142 }
143 }
144
145 dbus_connection_set_exit_on_disconnect(bus, FALSE);
146
147 if (private) {
148 if (bus_check_peercred(bus) < 0) {
149 dbus_connection_close(bus);
150 dbus_connection_unref(bus);
151
152 dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
153 return -EACCES;
154 }
155 }
156
157 r = sync_auth(bus, error);
158 if (r < 0) {
159 dbus_connection_close(bus);
160 dbus_connection_unref(bus);
161 return r;
162 }
163
164 if (_private)
165 *_private = private;
166
167 *_bus = bus;
168 return 0;
169 }
170
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;
175
176 assert(_bus);
177 assert(user || host);
178
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);
185
186 if (!p) {
187 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
188 return -ENOMEM;
189 }
190
191 bus = dbus_connection_open_private(p, error);
192 free(p);
193
194 if (!bus)
195 return -EIO;
196
197 dbus_connection_set_exit_on_disconnect(bus, FALSE);
198
199 if ((r = sync_auth(bus, error)) < 0) {
200 dbus_connection_close(bus);
201 dbus_connection_unref(bus);
202 return r;
203 }
204
205 if (!dbus_bus_register(bus, error)) {
206 dbus_connection_close(bus);
207 dbus_connection_unref(bus);
208 return r;
209 }
210
211 *_bus = bus;
212 return 0;
213 }
214
215 int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
216 DBusConnection *bus;
217 int r;
218
219 assert(_bus);
220
221 /* Don't bother with PolicyKit if we are root */
222 if (geteuid() == 0)
223 return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
224
225 bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
226 if (!bus)
227 return -EIO;
228
229 dbus_connection_set_exit_on_disconnect(bus, FALSE);
230
231 if ((r = sync_auth(bus, error)) < 0) {
232 dbus_connection_close(bus);
233 dbus_connection_unref(bus);
234 return r;
235 }
236
237 if (!dbus_bus_register(bus, error)) {
238 dbus_connection_close(bus);
239 dbus_connection_unref(bus);
240 return r;
241 }
242
243 *_bus = bus;
244 return 0;
245 }
246
247 const char *bus_error_message(const DBusError *error) {
248 assert(error);
249
250 /* Sometimes the D-Bus server is a little bit too verbose with
251 * its error messages, so let's override them here */
252 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
253 return "Access denied";
254
255 return error->message;
256 }
257
258 DBusHandlerResult bus_default_message_handler(
259 DBusConnection *c,
260 DBusMessage *message,
261 const char *introspection,
262 const char *interfaces,
263 const BusBoundProperties *bound_properties) {
264
265 DBusError error;
266 DBusMessage *reply = NULL;
267 int r;
268
269 assert(c);
270 assert(message);
271
272 dbus_error_init(&error);
273
274 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
275
276 if (!(reply = dbus_message_new_method_return(message)))
277 goto oom;
278
279 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
280 goto oom;
281
282 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
283 const char *interface, *property;
284 const BusBoundProperties *bp;
285 const BusProperty *p;
286 void *data;
287 DBusMessageIter iter, sub;
288
289 if (!dbus_message_get_args(
290 message,
291 &error,
292 DBUS_TYPE_STRING, &interface,
293 DBUS_TYPE_STRING, &property,
294 DBUS_TYPE_INVALID))
295 return bus_send_error_reply(c, message, &error, -EINVAL);
296
297 for (bp = bound_properties; bp->interface; bp++) {
298 if (!streq(bp->interface, interface))
299 continue;
300
301 for (p = bp->properties; p->property; p++)
302 if (streq(p->property, property))
303 goto get_prop;
304 }
305
306 /* no match */
307 if (!nulstr_contains(interfaces, interface))
308 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
309 else
310 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
311
312 return bus_send_error_reply(c, message, &error, -EINVAL);
313
314 get_prop:
315 reply = dbus_message_new_method_return(message);
316 if (!reply)
317 goto oom;
318
319 dbus_message_iter_init_append(reply, &iter);
320
321 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
322 goto oom;
323
324 data = (char*)bp->base + p->offset;
325 if (p->indirect)
326 data = *(void**)data;
327 r = p->append(&sub, property, data);
328 if (r < 0) {
329 if (r == -ENOMEM)
330 goto oom;
331
332 dbus_message_unref(reply);
333 return bus_send_error_reply(c, message, NULL, r);
334 }
335
336 if (!dbus_message_iter_close_container(&iter, &sub))
337 goto oom;
338
339 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
340 const char *interface;
341 const BusBoundProperties *bp;
342 const BusProperty *p;
343 DBusMessageIter iter, sub, sub2, sub3;
344
345 if (!dbus_message_get_args(
346 message,
347 &error,
348 DBUS_TYPE_STRING, &interface,
349 DBUS_TYPE_INVALID))
350 return bus_send_error_reply(c, message, &error, -EINVAL);
351
352 if (interface[0] && !nulstr_contains(interfaces, interface)) {
353 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
354 return bus_send_error_reply(c, message, &error, -EINVAL);
355 }
356
357 if (!(reply = dbus_message_new_method_return(message)))
358 goto oom;
359
360 dbus_message_iter_init_append(reply, &iter);
361
362 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
363 goto oom;
364
365 for (bp = bound_properties; bp->interface; bp++) {
366 if (interface[0] && !streq(bp->interface, interface))
367 continue;
368
369 for (p = bp->properties; p->property; p++) {
370 void *data;
371
372 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
373 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
374 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
375 goto oom;
376
377 data = (char*)bp->base + p->offset;
378 if (p->indirect)
379 data = *(void**)data;
380 r = p->append(&sub3, p->property, data);
381 if (r < 0) {
382 if (r == -ENOMEM)
383 goto oom;
384
385 dbus_message_unref(reply);
386 return bus_send_error_reply(c, message, NULL, r);
387 }
388
389 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
390 !dbus_message_iter_close_container(&sub, &sub2))
391 goto oom;
392 }
393 }
394
395 if (!dbus_message_iter_close_container(&iter, &sub))
396 goto oom;
397
398 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
399 const char *interface, *property;
400 DBusMessageIter iter;
401 const BusBoundProperties *bp;
402 const BusProperty *p;
403 DBusMessageIter sub;
404 char *sig;
405 void *data;
406
407 if (!dbus_message_iter_init(message, &iter) ||
408 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
409 return bus_send_error_reply(c, message, NULL, -EINVAL);
410
411 dbus_message_iter_get_basic(&iter, &interface);
412
413 if (!dbus_message_iter_next(&iter) ||
414 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
415 return bus_send_error_reply(c, message, NULL, -EINVAL);
416
417 dbus_message_iter_get_basic(&iter, &property);
418
419 if (!dbus_message_iter_next(&iter) ||
420 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
421 dbus_message_iter_has_next(&iter))
422 return bus_send_error_reply(c, message, NULL, -EINVAL);
423
424 for (bp = bound_properties; bp->interface; bp++) {
425 if (!streq(bp->interface, interface))
426 continue;
427
428 for (p = bp->properties; p->property; p++)
429 if (streq(p->property, property))
430 goto set_prop;
431 }
432
433 /* no match */
434 if (!nulstr_contains(interfaces, interface))
435 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
436 else
437 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
438
439 return bus_send_error_reply(c, message, &error, -EINVAL);
440
441 set_prop:
442 if (!p->set) {
443 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
444 return bus_send_error_reply(c, message, &error, -EINVAL);
445 }
446
447 dbus_message_iter_recurse(&iter, &sub);
448
449 sig = dbus_message_iter_get_signature(&sub);
450 if (!sig)
451 goto oom;
452
453 if (!streq(sig, p->signature)) {
454 dbus_free(sig);
455 return bus_send_error_reply(c, message, NULL, -EINVAL);
456 }
457
458 dbus_free(sig);
459
460 data = (char*)bp->base + p->offset;
461 if (p->indirect)
462 data = *(void**)data;
463 r = p->set(&sub, property, data);
464 if (r < 0) {
465 if (r == -ENOMEM)
466 goto oom;
467 return bus_send_error_reply(c, message, NULL, r);
468 }
469
470 reply = dbus_message_new_method_return(message);
471 if (!reply)
472 goto oom;
473 } else {
474 const char *interface = dbus_message_get_interface(message);
475
476 if (!interface || !nulstr_contains(interfaces, interface)) {
477 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
478 return bus_send_error_reply(c, message, &error, -EINVAL);
479 }
480 }
481
482 if (reply) {
483 if (!dbus_connection_send(c, reply, NULL))
484 goto oom;
485
486 dbus_message_unref(reply);
487 return DBUS_HANDLER_RESULT_HANDLED;
488 }
489
490 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
491
492 oom:
493 if (reply)
494 dbus_message_unref(reply);
495
496 dbus_error_free(&error);
497
498 return DBUS_HANDLER_RESULT_NEED_MEMORY;
499 }
500
501 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
502 const char *t = data;
503
504 assert(i);
505 assert(property);
506
507 if (!t)
508 t = "";
509
510 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
511 return -ENOMEM;
512
513 return 0;
514 }
515
516 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
517 char **t = data;
518
519 assert(i);
520 assert(property);
521
522 return bus_append_strv_iter(i, t);
523 }
524
525 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
526 bool *b = data;
527 dbus_bool_t db;
528
529 assert(i);
530 assert(property);
531 assert(b);
532
533 db = *b;
534
535 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
536 return -ENOMEM;
537
538 return 0;
539 }
540
541 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
542 int *b = data;
543 dbus_bool_t db;
544
545 assert(i);
546 assert(property);
547 assert(b);
548
549 db = *b > 0;
550
551 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
552 return -ENOMEM;
553
554 return 0;
555 }
556
557 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
558 assert(i);
559 assert(property);
560 assert(data);
561
562 /* Let's ensure that usec_t is actually 64bit, and hence this
563 * function can be used for usec_t */
564 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
565
566 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
567 return -ENOMEM;
568
569 return 0;
570 }
571
572 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
573 assert(i);
574 assert(property);
575 assert(data);
576
577 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
578 * 32bit, and hence this function can be used for
579 * pid_t/mode_t/uid_t/gid_t */
580 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
581 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
582 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
583 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
584 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
585
586 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
587 return -ENOMEM;
588
589 return 0;
590 }
591
592 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
593 assert(i);
594 assert(property);
595 assert(data);
596
597 assert_cc(sizeof(int32_t) == sizeof(int));
598
599 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
600 return -ENOMEM;
601
602 return 0;
603 }
604
605 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
606 uint64_t u;
607
608 assert(i);
609 assert(property);
610 assert(data);
611
612 u = (uint64_t) *(size_t*) data;
613
614 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
615 return -ENOMEM;
616
617 return 0;
618 }
619
620 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
621 uint64_t u;
622
623 assert(i);
624 assert(property);
625 assert(data);
626
627 u = (uint64_t) *(unsigned long*) data;
628
629 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
630 return -ENOMEM;
631
632 return 0;
633 }
634
635 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
636 int64_t l;
637
638 assert(i);
639 assert(property);
640 assert(data);
641
642 l = (int64_t) *(long*) data;
643
644 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
645 return -ENOMEM;
646
647 return 0;
648 }
649
650 const char *bus_errno_to_dbus(int error) {
651
652 switch(error) {
653
654 case -EINVAL:
655 return DBUS_ERROR_INVALID_ARGS;
656
657 case -ENOMEM:
658 return DBUS_ERROR_NO_MEMORY;
659
660 case -EPERM:
661 case -EACCES:
662 return DBUS_ERROR_ACCESS_DENIED;
663
664 case -ESRCH:
665 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
666
667 case -ENOENT:
668 return DBUS_ERROR_FILE_NOT_FOUND;
669
670 case -EEXIST:
671 return DBUS_ERROR_FILE_EXISTS;
672
673 case -ETIMEDOUT:
674 case -ETIME:
675 return DBUS_ERROR_TIMEOUT;
676
677 case -EIO:
678 return DBUS_ERROR_IO_ERROR;
679
680 case -ENETRESET:
681 case -ECONNABORTED:
682 case -ECONNRESET:
683 return DBUS_ERROR_DISCONNECTED;
684 }
685
686 return DBUS_ERROR_FAILED;
687 }
688
689 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
690 DBusMessage *reply = NULL;
691 const char *name, *text;
692
693 if (berror && dbus_error_is_set(berror)) {
694 name = berror->name;
695 text = berror->message;
696 } else {
697 name = bus_errno_to_dbus(error);
698 text = strerror(-error);
699 }
700
701 if (!(reply = dbus_message_new_error(message, name, text)))
702 goto oom;
703
704 if (!dbus_connection_send(c, reply, NULL))
705 goto oom;
706
707 dbus_message_unref(reply);
708
709 if (berror)
710 dbus_error_free(berror);
711
712 return DBUS_HANDLER_RESULT_HANDLED;
713
714 oom:
715 if (reply)
716 dbus_message_unref(reply);
717
718 if (berror)
719 dbus_error_free(berror);
720
721 return DBUS_HANDLER_RESULT_NEED_MEMORY;
722 }
723
724 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
725 DBusMessage *m;
726 DBusMessageIter iter, sub;
727 const char *i;
728
729 assert(interface);
730 assert(properties);
731
732 if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
733 goto oom;
734
735 dbus_message_iter_init_append(m, &iter);
736
737 /* We won't send any property values, since they might be
738 * large and sometimes not cheap to generated */
739
740 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
741 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
742 !dbus_message_iter_close_container(&iter, &sub) ||
743 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
744 goto oom;
745
746 NULSTR_FOREACH(i, properties)
747 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
748 goto oom;
749
750 if (!dbus_message_iter_close_container(&iter, &sub))
751 goto oom;
752
753 return m;
754
755 oom:
756 if (m)
757 dbus_message_unref(m);
758
759 return NULL;
760 }
761
762 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
763 unsigned flags;
764 uint32_t events = 0;
765
766 assert(bus_watch);
767
768 /* no watch flags for disabled watches */
769 if (!dbus_watch_get_enabled(bus_watch))
770 return 0;
771
772 flags = dbus_watch_get_flags(bus_watch);
773
774 if (flags & DBUS_WATCH_READABLE)
775 events |= EPOLLIN;
776 if (flags & DBUS_WATCH_WRITABLE)
777 events |= EPOLLOUT;
778
779 return events | EPOLLHUP | EPOLLERR;
780 }
781
782 unsigned bus_events_to_flags(uint32_t events) {
783 unsigned flags = 0;
784
785 if (events & EPOLLIN)
786 flags |= DBUS_WATCH_READABLE;
787 if (events & EPOLLOUT)
788 flags |= DBUS_WATCH_WRITABLE;
789 if (events & EPOLLHUP)
790 flags |= DBUS_WATCH_HANGUP;
791 if (events & EPOLLERR)
792 flags |= DBUS_WATCH_ERROR;
793
794 return flags;
795 }
796
797 int bus_parse_strv(DBusMessage *m, char ***_l) {
798 DBusMessageIter iter;
799
800 assert(m);
801 assert(_l);
802
803 if (!dbus_message_iter_init(m, &iter))
804 return -EINVAL;
805
806 return bus_parse_strv_iter(&iter, _l);
807 }
808
809 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
810 DBusMessageIter sub;
811 unsigned n = 0, i = 0;
812 char **l;
813
814 assert(iter);
815 assert(_l);
816
817 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
818 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
819 return -EINVAL;
820
821 dbus_message_iter_recurse(iter, &sub);
822
823 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
824 n++;
825 dbus_message_iter_next(&sub);
826 }
827
828 if (!(l = new(char*, n+1)))
829 return -ENOMEM;
830
831 dbus_message_iter_recurse(iter, &sub);
832
833 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
834 const char *s;
835
836 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
837 dbus_message_iter_get_basic(&sub, &s);
838
839 if (!(l[i++] = strdup(s))) {
840 strv_free(l);
841 return -ENOMEM;
842 }
843
844 dbus_message_iter_next(&sub);
845 }
846
847 assert(i == n);
848 l[i] = NULL;
849
850 if (_l)
851 *_l = l;
852
853 return 0;
854 }
855
856 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
857 DBusMessageIter sub;
858
859 assert(iter);
860
861 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
862 return -ENOMEM;
863
864 STRV_FOREACH(l, l)
865 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
866 return -ENOMEM;
867
868 if (!dbus_message_iter_close_container(iter, &sub))
869 return -ENOMEM;
870
871 return 0;
872 }
873
874 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
875
876 assert(iter);
877 assert(data);
878
879 if (dbus_message_iter_get_arg_type(iter) != type)
880 return -EIO;
881
882 dbus_message_iter_get_basic(iter, data);
883
884 if (!dbus_message_iter_next(iter) != !next)
885 return -EIO;
886
887 return 0;
888 }
889
890 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
891 assert(name);
892 assert(iter);
893
894 switch (dbus_message_iter_get_arg_type(iter)) {
895
896 case DBUS_TYPE_STRING: {
897 const char *s;
898 dbus_message_iter_get_basic(iter, &s);
899
900 if (all || !isempty(s))
901 printf("%s=%s\n", name, s);
902
903 return 1;
904 }
905
906 case DBUS_TYPE_BOOLEAN: {
907 dbus_bool_t b;
908
909 dbus_message_iter_get_basic(iter, &b);
910 printf("%s=%s\n", name, yes_no(b));
911
912 return 1;
913 }
914
915 case DBUS_TYPE_UINT64: {
916 uint64_t u;
917 dbus_message_iter_get_basic(iter, &u);
918
919 /* Yes, heuristics! But we can change this check
920 * should it turn out to not be sufficient */
921
922 if (endswith(name, "Timestamp")) {
923 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
924
925 t = format_timestamp(timestamp, sizeof(timestamp), u);
926 if (t || all)
927 printf("%s=%s\n", name, strempty(t));
928
929 } else if (strstr(name, "USec")) {
930 char timespan[FORMAT_TIMESPAN_MAX];
931
932 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
933 } else
934 printf("%s=%llu\n", name, (unsigned long long) u);
935
936 return 1;
937 }
938
939 case DBUS_TYPE_UINT32: {
940 uint32_t u;
941 dbus_message_iter_get_basic(iter, &u);
942
943 if (strstr(name, "UMask") || strstr(name, "Mode"))
944 printf("%s=%04o\n", name, u);
945 else
946 printf("%s=%u\n", name, (unsigned) u);
947
948 return 1;
949 }
950
951 case DBUS_TYPE_INT32: {
952 int32_t i;
953 dbus_message_iter_get_basic(iter, &i);
954
955 printf("%s=%i\n", name, (int) i);
956 return 1;
957 }
958
959 case DBUS_TYPE_DOUBLE: {
960 double d;
961 dbus_message_iter_get_basic(iter, &d);
962
963 printf("%s=%g\n", name, d);
964 return 1;
965 }
966
967 case DBUS_TYPE_ARRAY:
968
969 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
970 DBusMessageIter sub;
971 bool space = false;
972
973 dbus_message_iter_recurse(iter, &sub);
974 if (all ||
975 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
976 printf("%s=", name);
977
978 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
979 const char *s;
980
981 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
982 dbus_message_iter_get_basic(&sub, &s);
983 printf("%s%s", space ? " " : "", s);
984
985 space = true;
986 dbus_message_iter_next(&sub);
987 }
988
989 puts("");
990 }
991
992 return 1;
993
994 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
995 DBusMessageIter sub;
996
997 dbus_message_iter_recurse(iter, &sub);
998 if (all ||
999 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1000 printf("%s=", name);
1001
1002 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1003 uint8_t u;
1004
1005 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1006 dbus_message_iter_get_basic(&sub, &u);
1007 printf("%02x", u);
1008
1009 dbus_message_iter_next(&sub);
1010 }
1011
1012 puts("");
1013 }
1014
1015 return 1;
1016 }
1017
1018 break;
1019 }
1020
1021 return 0;
1022 }
1023
1024 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1025 DBusMessage *reply;
1026 DBusConnection *bus = userdata;
1027
1028 assert_se(reply = dbus_pending_call_steal_reply(pending));
1029 dbus_message_unref(reply);
1030
1031 dbus_connection_close(bus);
1032 }
1033
1034 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1035 DBusMessage *m = NULL;
1036 DBusPendingCall *pending = NULL;
1037
1038 assert(bus);
1039
1040 /* We unregister the name here, but we continue to process
1041 * requests, until we get the response for it, so that all
1042 * requests are guaranteed to be processed. */
1043
1044 m = dbus_message_new_method_call(
1045 DBUS_SERVICE_DBUS,
1046 DBUS_PATH_DBUS,
1047 DBUS_INTERFACE_DBUS,
1048 "ReleaseName");
1049 if (!m)
1050 goto oom;
1051
1052 if (!dbus_message_append_args(
1053 m,
1054 DBUS_TYPE_STRING,
1055 &name,
1056 DBUS_TYPE_INVALID))
1057 goto oom;
1058
1059 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1060 goto oom;
1061
1062 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1063 goto oom;
1064
1065 dbus_message_unref(m);
1066 dbus_pending_call_unref(pending);
1067
1068 return;
1069
1070 oom:
1071 log_error("Out of memory");
1072
1073 if (pending) {
1074 dbus_pending_call_cancel(pending);
1075 dbus_pending_call_unref(pending);
1076 }
1077
1078 if (m)
1079 dbus_message_unref(m);
1080 }
1081
1082 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1083 usec_t *remain_until = userdata;
1084
1085 assert(bus);
1086 assert(m);
1087 assert(remain_until);
1088
1089 /* Everytime we get a new message we reset out timeout */
1090 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1091
1092 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1093 dbus_connection_close(bus);
1094
1095 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1096 }