]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dbus-common.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / shared / dbus-common.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
9a1ac7b9
LP
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
5430f7f2
LP
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
9a1ac7b9
LP
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
5430f7f2 16 Lesser General Public License for more details.
9a1ac7b9 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
9a1ac7b9
LP
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>
a8f11321
LP
26#include <stdio.h>
27#include <stdlib.h>
9a1ac7b9 28#include <dbus/dbus.h>
bfebab7f 29#include <string.h>
3df5bf61 30#include <sys/epoll.h>
9a1ac7b9
LP
31
32#include "log.h"
33#include "dbus-common.h"
b9978121 34#include "util.h"
f6a6225e 35#include "def.h"
bfebab7f 36#include "strv.h"
9a1ac7b9
LP
37
38int 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
be81bfc4 58 if (ucred.uid != 0 && ucred.uid != geteuid())
9a1ac7b9
LP
59 return -EPERM;
60
61 return 1;
62}
63
a8f11321
LP
64static int sync_auth(DBusConnection *bus, DBusError *error) {
65 usec_t begin, tstamp;
9a1ac7b9 66
a8f11321 67 assert(bus);
b9978121 68
a8f11321
LP
69 /* This complexity should probably move into D-Bus itself:
70 *
71 * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
9a1ac7b9 72
a8f11321
LP
73 begin = tstamp = now(CLOCK_MONOTONIC);
74 for (;;) {
9a1ac7b9 75
f6a6225e 76 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
a8f11321 77 break;
9a1ac7b9 78
a8f11321
LP
79 if (dbus_connection_get_is_authenticated(bus))
80 break;
f4579ce7 81
f6a6225e 82 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
a8f11321 83 break;
b9978121 84
a8f11321
LP
85 tstamp = now(CLOCK_MONOTONIC);
86 }
b9978121 87
a8f11321
LP
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 }
b9978121 92
a8f11321
LP
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 }
b9978121 97
a8f11321
LP
98 return 0;
99}
b9978121 100
be81bfc4
LP
101int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
102 DBusConnection *bus = NULL;
a8f11321 103 int r;
be81bfc4 104 bool private = true;
b9978121 105
a8f11321 106 assert(_bus);
b9978121 107
a8f11321 108 if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
be81bfc4
LP
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;
91b22f21 119
be81bfc4
LP
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 }
91b22f21 135
be81bfc4
LP
136 if (!bus) {
137 bus = dbus_bus_get_private(t, error);
138 if (!bus)
91b22f21 139 return -EIO;
be81bfc4
LP
140
141 private = false;
91b22f21 142 }
be81bfc4 143 }
a8f11321 144
be81bfc4 145 dbus_connection_set_exit_on_disconnect(bus, FALSE);
a8f11321 146
be81bfc4 147 if (private) {
a8f11321 148 if (bus_check_peercred(bus) < 0) {
b9978121
LP
149 dbus_connection_close(bus);
150 dbus_connection_unref(bus);
151
a8f11321 152 dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
b9978121
LP
153 return -EACCES;
154 }
9a1ac7b9
LP
155 }
156
be81bfc4
LP
157 r = sync_auth(bus, error);
158 if (r < 0) {
a8f11321
LP
159 dbus_connection_close(bus);
160 dbus_connection_unref(bus);
161 return r;
162 }
163
be81bfc4
LP
164 if (_private)
165 *_private = private;
166
a8f11321
LP
167 *_bus = bus;
168 return 0;
169}
170
171int 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)
72e764a6 180 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
a8f11321 181 else if (user)
72e764a6 182 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
a8f11321 183 else if (host)
72e764a6 184 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
a8f11321
LP
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
215int 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
72e764a6
LP
225 bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
226 if (!bus)
a8f11321
LP
227 return -EIO;
228
9a1ac7b9
LP
229 dbus_connection_set_exit_on_disconnect(bus, FALSE);
230
a8f11321
LP
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
9a1ac7b9
LP
243 *_bus = bus;
244 return 0;
245}
4cf5d675
LP
246
247const char *bus_error_message(const DBusError *error) {
eecd1362
LP
248 if (!error)
249 return NULL;
4cf5d675
LP
250
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";
255
256 return error->message;
257}
bfebab7f 258
eecd1362
LP
259const char *bus_error_message_or_strerror(const DBusError *error, int err) {
260
261 if (error && dbus_error_is_set(error))
262 return bus_error_message(error);
263
264 return strerror(err);
265}
266
bfebab7f
LP
267DBusHandlerResult bus_default_message_handler(
268 DBusConnection *c,
269 DBusMessage *message,
270 const char *introspection,
271 const char *interfaces,
d200735e 272 const BusBoundProperties *bound_properties) {
bfebab7f
LP
273
274 DBusError error;
275 DBusMessage *reply = NULL;
276 int r;
277
278 assert(c);
279 assert(message);
280
281 dbus_error_init(&error);
282
283 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
284
285 if (!(reply = dbus_message_new_method_return(message)))
286 goto oom;
287
288 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
289 goto oom;
290
d200735e 291 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
bfebab7f 292 const char *interface, *property;
d200735e 293 const BusBoundProperties *bp;
bfebab7f 294 const BusProperty *p;
d200735e
MS
295 void *data;
296 DBusMessageIter iter, sub;
bfebab7f
LP
297
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);
305
d200735e
MS
306 for (bp = bound_properties; bp->interface; bp++) {
307 if (!streq(bp->interface, interface))
308 continue;
bfebab7f 309
d200735e
MS
310 for (p = bp->properties; p->property; p++)
311 if (streq(p->property, property))
312 goto get_prop;
313 }
bfebab7f 314
d200735e
MS
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");
bfebab7f 320
d200735e 321 return bus_send_error_reply(c, message, &error, -EINVAL);
bfebab7f 322
d200735e
MS
323get_prop:
324 reply = dbus_message_new_method_return(message);
325 if (!reply)
326 goto oom;
bfebab7f 327
d200735e 328 dbus_message_iter_init_append(reply, &iter);
bfebab7f 329
d200735e
MS
330 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
331 goto oom;
bfebab7f 332
d200735e
MS
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)
bfebab7f 339 goto oom;
bfebab7f 340
d200735e
MS
341 dbus_message_unref(reply);
342 return bus_send_error_reply(c, message, NULL, r);
bfebab7f
LP
343 }
344
d200735e
MS
345 if (!dbus_message_iter_close_container(&iter, &sub))
346 goto oom;
347
348 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
bfebab7f 349 const char *interface;
d200735e 350 const BusBoundProperties *bp;
bfebab7f
LP
351 const BusProperty *p;
352 DBusMessageIter iter, sub, sub2, sub3;
353
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);
360
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);
364 }
365
366 if (!(reply = dbus_message_new_method_return(message)))
367 goto oom;
368
369 dbus_message_iter_init_append(reply, &iter);
370
371 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
372 goto oom;
373
d200735e
MS
374 for (bp = bound_properties; bp->interface; bp++) {
375 if (interface[0] && !streq(bp->interface, interface))
bfebab7f
LP
376 continue;
377
d200735e
MS
378 for (p = bp->properties; p->property; p++) {
379 void *data;
bfebab7f 380
d200735e
MS
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))
bfebab7f
LP
384 goto oom;
385
d200735e
MS
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;
bfebab7f 393
d200735e
MS
394 dbus_message_unref(reply);
395 return bus_send_error_reply(c, message, NULL, r);
396 }
397
398 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
399 !dbus_message_iter_close_container(&sub, &sub2))
400 goto oom;
401 }
bfebab7f
LP
402 }
403
404 if (!dbus_message_iter_close_container(&iter, &sub))
405 goto oom;
406
d200735e 407 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
bfebab7f
LP
408 const char *interface, *property;
409 DBusMessageIter iter;
d200735e 410 const BusBoundProperties *bp;
bfebab7f 411 const BusProperty *p;
d200735e
MS
412 DBusMessageIter sub;
413 char *sig;
9612f07c 414 void *data;
d4e7373b 415 DBusMessage *changed;
bfebab7f
LP
416
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);
420
421 dbus_message_iter_get_basic(&iter, &interface);
422
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);
426
427 dbus_message_iter_get_basic(&iter, &property);
428
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);
433
d200735e
MS
434 for (bp = bound_properties; bp->interface; bp++) {
435 if (!streq(bp->interface, interface))
436 continue;
437
438 for (p = bp->properties; p->property; p++)
439 if (streq(p->property, property))
440 goto set_prop;
441 }
bfebab7f 442
d200735e
MS
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");
bfebab7f 448
d200735e 449 return bus_send_error_reply(c, message, &error, -EINVAL);
bfebab7f 450
d200735e
MS
451set_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);
455 }
bfebab7f 456
d200735e 457 dbus_message_iter_recurse(&iter, &sub);
bfebab7f 458
d200735e
MS
459 sig = dbus_message_iter_get_signature(&sub);
460 if (!sig)
461 goto oom;
462
463 if (!streq(sig, p->signature)) {
bfebab7f 464 dbus_free(sig);
d200735e
MS
465 return bus_send_error_reply(c, message, NULL, -EINVAL);
466 }
d200735e 467 dbus_free(sig);
bfebab7f 468
d4e7373b 469 data = (uint8_t*) bp->base + p->offset;
9612f07c
MO
470 if (p->indirect)
471 data = *(void**)data;
d4e7373b 472
9612f07c 473 r = p->set(&sub, property, data);
d4e7373b
LP
474 if (r == -ENOMEM)
475 goto oom;
476 else if (r < 0)
d200735e 477 return bus_send_error_reply(c, message, NULL, r);
bfebab7f 478
d200735e
MS
479 reply = dbus_message_new_method_return(message);
480 if (!reply)
481 goto oom;
d4e7373b
LP
482
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);
492 }
493
494
cda2b84a
MS
495 } else {
496 const char *interface = dbus_message_get_interface(message);
497
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);
501 }
bfebab7f
LP
502 }
503
504 if (reply) {
505 if (!dbus_connection_send(c, reply, NULL))
506 goto oom;
507
508 dbus_message_unref(reply);
509 return DBUS_HANDLER_RESULT_HANDLED;
510 }
511
512 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
513
514oom:
515 if (reply)
516 dbus_message_unref(reply);
517
518 dbus_error_free(&error);
519
520 return DBUS_HANDLER_RESULT_NEED_MEMORY;
521}
522
523int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
524 const char *t = data;
525
526 assert(i);
527 assert(property);
528
529 if (!t)
530 t = "";
531
532 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
533 return -ENOMEM;
534
535 return 0;
536}
537
538int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
bfebab7f
LP
539 char **t = data;
540
541 assert(i);
542 assert(property);
543
98a28fef 544 return bus_append_strv_iter(i, t);
bfebab7f
LP
545}
546
547int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
548 bool *b = data;
549 dbus_bool_t db;
550
551 assert(i);
552 assert(property);
553 assert(b);
554
555 db = *b;
556
557 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
558 return -ENOMEM;
559
560 return 0;
561}
562
aa001cd6
LP
563int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
564 int *b = data;
565 dbus_bool_t db;
566
567 assert(i);
568 assert(property);
569 assert(b);
570
571 db = *b > 0;
572
573 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
574 return -ENOMEM;
575
576 return 0;
577}
578
bfebab7f
LP
579int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
580 assert(i);
581 assert(property);
582 assert(data);
583
bd253d1b 584 /* Let's ensure that usec_t is actually 64bit, and hence this
bfebab7f
LP
585 * function can be used for usec_t */
586 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
587
588 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
589 return -ENOMEM;
590
591 return 0;
592}
593
594int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
595 assert(i);
596 assert(property);
597 assert(data);
598
bd253d1b
LP
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 */
bfebab7f
LP
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));
bd253d1b
LP
605 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
606 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
bfebab7f
LP
607
608 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
609 return -ENOMEM;
610
611 return 0;
612}
613
614int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
615 assert(i);
616 assert(property);
617 assert(data);
618
619 assert_cc(sizeof(int32_t) == sizeof(int));
620
621 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
622 return -ENOMEM;
623
624 return 0;
625}
626
627int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
628 uint64_t u;
629
630 assert(i);
631 assert(property);
632 assert(data);
633
634 u = (uint64_t) *(size_t*) data;
635
636 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
637 return -ENOMEM;
638
639 return 0;
640}
641
642int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
643 uint64_t u;
644
645 assert(i);
646 assert(property);
647 assert(data);
648
649 u = (uint64_t) *(unsigned long*) data;
650
651 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
652 return -ENOMEM;
916abb21
LP
653
654 return 0;
655}
656
657int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
572481b9 658 int64_t l;
916abb21
LP
659
660 assert(i);
661 assert(property);
662 assert(data);
663
572481b9 664 l = (int64_t) *(long*) data;
916abb21 665
572481b9 666 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
916abb21 667 return -ENOMEM;
bfebab7f
LP
668
669 return 0;
670}
671
c757a65b
LP
672int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
673 uint64_t *t = data;
674
675 assert(i);
676 assert(property);
677
678 dbus_message_iter_get_basic(i, t);
679 return 0;
680}
681
bfebab7f
LP
682const char *bus_errno_to_dbus(int error) {
683
684 switch(error) {
685
686 case -EINVAL:
687 return DBUS_ERROR_INVALID_ARGS;
688
689 case -ENOMEM:
690 return DBUS_ERROR_NO_MEMORY;
691
692 case -EPERM:
693 case -EACCES:
694 return DBUS_ERROR_ACCESS_DENIED;
695
696 case -ESRCH:
697 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
698
699 case -ENOENT:
700 return DBUS_ERROR_FILE_NOT_FOUND;
701
702 case -EEXIST:
703 return DBUS_ERROR_FILE_EXISTS;
704
705 case -ETIMEDOUT:
706 case -ETIME:
707 return DBUS_ERROR_TIMEOUT;
708
709 case -EIO:
710 return DBUS_ERROR_IO_ERROR;
711
712 case -ENETRESET:
713 case -ECONNABORTED:
714 case -ECONNRESET:
715 return DBUS_ERROR_DISCONNECTED;
716 }
717
718 return DBUS_ERROR_FAILED;
719}
720
721DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
722 DBusMessage *reply = NULL;
723 const char *name, *text;
724
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);
731 }
732
733 if (!(reply = dbus_message_new_error(message, name, text)))
734 goto oom;
735
736 if (!dbus_connection_send(c, reply, NULL))
737 goto oom;
738
739 dbus_message_unref(reply);
740
741 if (berror)
742 dbus_error_free(berror);
743
744 return DBUS_HANDLER_RESULT_HANDLED;
745
746oom:
747 if (reply)
748 dbus_message_unref(reply);
749
750 if (berror)
751 dbus_error_free(berror);
752
753 return DBUS_HANDLER_RESULT_NEED_MEMORY;
754}
755
756DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
757 DBusMessage *m;
758 DBusMessageIter iter, sub;
759 const char *i;
760
761 assert(interface);
762 assert(properties);
763
d4e7373b
LP
764 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
765 if (!m)
bfebab7f
LP
766 goto oom;
767
768 dbus_message_iter_init_append(m, &iter);
769
770 /* We won't send any property values, since they might be
771 * large and sometimes not cheap to generated */
772
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;
778
779 NULSTR_FOREACH(i, properties)
780 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
781 goto oom;
782
783 if (!dbus_message_iter_close_container(&iter, &sub))
784 goto oom;
785
786 return m;
787
788oom:
789 if (m)
790 dbus_message_unref(m);
791
792 return NULL;
793}
3df5bf61 794
d4e7373b
LP
795DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
796 DBusMessage *m;
797 DBusMessageIter iter, sub;
798
799 assert(interface);
800 assert(property);
801
802 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
803 if (!m)
804 goto oom;
805
806 dbus_message_iter_init_append(m, &iter);
807
808 /* We won't send any property values, since they might be
809 * large and sometimes not cheap to generated */
810
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;
816
817 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
818 goto oom;
819
820 if (!dbus_message_iter_close_container(&iter, &sub))
821 goto oom;
822
823 return m;
824
825oom:
826 if (m)
827 dbus_message_unref(m);
828
829 return NULL;
830}
831
3df5bf61
LP
832uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
833 unsigned flags;
834 uint32_t events = 0;
835
836 assert(bus_watch);
837
838 /* no watch flags for disabled watches */
839 if (!dbus_watch_get_enabled(bus_watch))
840 return 0;
841
842 flags = dbus_watch_get_flags(bus_watch);
843
844 if (flags & DBUS_WATCH_READABLE)
845 events |= EPOLLIN;
846 if (flags & DBUS_WATCH_WRITABLE)
847 events |= EPOLLOUT;
848
849 return events | EPOLLHUP | EPOLLERR;
850}
851
852unsigned bus_events_to_flags(uint32_t events) {
853 unsigned flags = 0;
854
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;
863
864 return flags;
865}
8d0e38a2
LP
866
867int bus_parse_strv(DBusMessage *m, char ***_l) {
868 DBusMessageIter iter;
869
870 assert(m);
871 assert(_l);
872
873 if (!dbus_message_iter_init(m, &iter))
874 return -EINVAL;
875
876 return bus_parse_strv_iter(&iter, _l);
877}
878
879int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
880 DBusMessageIter sub;
881 unsigned n = 0, i = 0;
882 char **l;
883
884 assert(iter);
885 assert(_l);
886
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;
890
891 dbus_message_iter_recurse(iter, &sub);
892
893 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
894 n++;
895 dbus_message_iter_next(&sub);
896 }
897
898 if (!(l = new(char*, n+1)))
899 return -ENOMEM;
900
901 dbus_message_iter_recurse(iter, &sub);
902
903 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
904 const char *s;
905
906 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
907 dbus_message_iter_get_basic(&sub, &s);
908
909 if (!(l[i++] = strdup(s))) {
910 strv_free(l);
911 return -ENOMEM;
912 }
913
914 dbus_message_iter_next(&sub);
915 }
916
917 assert(i == n);
918 l[i] = NULL;
919
920 if (_l)
921 *_l = l;
922
923 return 0;
924}
98a28fef
LP
925
926int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
927 DBusMessageIter sub;
928
929 assert(iter);
930
931 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
932 return -ENOMEM;
933
934 STRV_FOREACH(l, l)
935 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
936 return -ENOMEM;
937
938 if (!dbus_message_iter_close_container(iter, &sub))
939 return -ENOMEM;
940
941 return 0;
942}
abca4822
LP
943
944int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
945
946 assert(iter);
947 assert(data);
948
949 if (dbus_message_iter_get_arg_type(iter) != type)
950 return -EIO;
951
952 dbus_message_iter_get_basic(iter, data);
953
954 if (!dbus_message_iter_next(iter) != !next)
955 return -EIO;
956
957 return 0;
958}
a4c279f8
LP
959
960int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
961 assert(name);
962 assert(iter);
963
964 switch (dbus_message_iter_get_arg_type(iter)) {
965
966 case DBUS_TYPE_STRING: {
967 const char *s;
968 dbus_message_iter_get_basic(iter, &s);
969
970 if (all || !isempty(s))
971 printf("%s=%s\n", name, s);
972
973 return 1;
974 }
975
976 case DBUS_TYPE_BOOLEAN: {
977 dbus_bool_t b;
978
979 dbus_message_iter_get_basic(iter, &b);
980 printf("%s=%s\n", name, yes_no(b));
981
982 return 1;
983 }
984
985 case DBUS_TYPE_UINT64: {
986 uint64_t u;
987 dbus_message_iter_get_basic(iter, &u);
988
989 /* Yes, heuristics! But we can change this check
990 * should it turn out to not be sufficient */
991
992 if (endswith(name, "Timestamp")) {
993 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
994
995 t = format_timestamp(timestamp, sizeof(timestamp), u);
996 if (t || all)
997 printf("%s=%s\n", name, strempty(t));
998
999 } else if (strstr(name, "USec")) {
1000 char timespan[FORMAT_TIMESPAN_MAX];
1001
1002 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1003 } else
1004 printf("%s=%llu\n", name, (unsigned long long) u);
1005
1006 return 1;
1007 }
1008
1009 case DBUS_TYPE_UINT32: {
1010 uint32_t u;
1011 dbus_message_iter_get_basic(iter, &u);
1012
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);
1017
1018 return 1;
1019 }
1020
1021 case DBUS_TYPE_INT32: {
1022 int32_t i;
1023 dbus_message_iter_get_basic(iter, &i);
1024
1025 printf("%s=%i\n", name, (int) i);
1026 return 1;
1027 }
1028
1029 case DBUS_TYPE_DOUBLE: {
1030 double d;
1031 dbus_message_iter_get_basic(iter, &d);
1032
1033 printf("%s=%g\n", name, d);
1034 return 1;
1035 }
1036
1037 case DBUS_TYPE_ARRAY:
1038
1039 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1040 DBusMessageIter sub;
1041 bool space = false;
1042
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);
1047
1048 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1049 const char *s;
1050
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);
1054
1055 space = true;
1056 dbus_message_iter_next(&sub);
1057 }
1058
1059 puts("");
1060 }
1061
1062 return 1;
1063
1064 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1065 DBusMessageIter sub;
1066
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);
1071
1072 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1073 uint8_t u;
1074
1075 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1076 dbus_message_iter_get_basic(&sub, &u);
1077 printf("%02x", u);
1078
1079 dbus_message_iter_next(&sub);
1080 }
1081
1082 puts("");
1083 }
1084
8351ceae
LP
1085 return 1;
1086
1087 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1088 DBusMessageIter sub;
1089
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);
1094
1095 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1096 uint32_t u;
1097
1098 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1099 dbus_message_iter_get_basic(&sub, &u);
1100 printf("%08x", u);
1101
1102 dbus_message_iter_next(&sub);
1103 }
1104
1105 puts("");
1106 }
1107
a4c279f8
LP
1108 return 1;
1109 }
1110
1111 break;
1112 }
1113
1114 return 0;
1115}
ad740100
LP
1116
1117static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1118 DBusMessage *reply;
1119 DBusConnection *bus = userdata;
1120
1121 assert_se(reply = dbus_pending_call_steal_reply(pending));
1122 dbus_message_unref(reply);
1123
1124 dbus_connection_close(bus);
1125}
1126
1127void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1128 DBusMessage *m = NULL;
1129 DBusPendingCall *pending = NULL;
1130
1131 assert(bus);
1132
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. */
1136
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;
1144
1145 if (!dbus_message_append_args(
1146 m,
1147 DBUS_TYPE_STRING,
1148 &name,
1149 DBUS_TYPE_INVALID))
1150 goto oom;
1151
1152 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1153 goto oom;
1154
1155 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1156 goto oom;
1157
1158 dbus_message_unref(m);
1159 dbus_pending_call_unref(pending);
1160
1161 return;
1162
1163oom:
669241a0 1164 log_error("Out of memory.");
ad740100
LP
1165
1166 if (pending) {
1167 dbus_pending_call_cancel(pending);
1168 dbus_pending_call_unref(pending);
1169 }
1170
1171 if (m)
1172 dbus_message_unref(m);
1173}
1174
1175DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1176 usec_t *remain_until = userdata;
1177
1178 assert(bus);
1179 assert(m);
1180 assert(remain_until);
1181
49f43d5f 1182 /* Every time we get a new message we reset out timeout */
ad740100
LP
1183 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1184
1185 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1186 dbus_connection_close(bus);
1187
1188 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1189}
f8e2fb7b
LP
1190
1191/* This mimics dbus_bus_get_unix_user() */
1192pid_t bus_get_unix_process_id(
1193 DBusConnection *connection,
1194 const char *name,
1195 DBusError *error) {
1196
1197 DBusMessage *m = NULL, *reply = NULL;
1198 uint32_t pid = 0;
1199
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;
1208 }
1209
1210 if (!dbus_message_append_args(
1211 m,
1212 DBUS_TYPE_STRING, &name,
1213 DBUS_TYPE_INVALID)) {
1214 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1215 goto finish;
1216 }
1217
1218 reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1219 if (!reply)
1220 goto finish;
1221
1222 if (dbus_set_error_from_message(error, reply))
1223 goto finish;
1224
1225 if (!dbus_message_get_args(
1226 reply, error,
1227 DBUS_TYPE_UINT32, &pid,
1228 DBUS_TYPE_INVALID))
1229 goto finish;
1230
1231finish:
1232 if (m)
1233 dbus_message_unref(m);
1234
1235 if (reply)
1236 dbus_message_unref(reply);
1237
1238 return (pid_t) pid;
1239}