]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/dbus.c
label: fix labeling of symbolic links
[thirdparty/systemd.git] / src / dbus.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986
LP
22#include <sys/epoll.h>
23#include <sys/timerfd.h>
24#include <errno.h>
25#include <unistd.h>
4139c1b2 26#include <dbus/dbus.h>
ea430986
LP
27
28#include "dbus.h"
29#include "log.h"
30#include "strv.h"
8e274523 31#include "cgroup.h"
4139c1b2
LP
32#include "dbus-unit.h"
33#include "dbus-job.h"
34#include "dbus-manager.h"
4288f619
LP
35#include "dbus-service.h"
36#include "dbus-socket.h"
37#include "dbus-target.h"
38#include "dbus-device.h"
39#include "dbus-mount.h"
40#include "dbus-automount.h"
41#include "dbus-snapshot.h"
42#include "dbus-swap.h"
871d7de4 43#include "dbus-timer.h"
01f78473 44#include "dbus-path.h"
398ef8ba 45#include "bus-errors.h"
8f6df3fa 46#include "special.h"
bfebab7f 47#include "dbus-common.h"
4288f619 48
5e8d1c9a
LP
49#define CONNECTIONS_MAX 52
50
4288f619
LP
51static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
52static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
53
54const char *const bus_interface_table[] = {
55 "org.freedesktop.DBus.Properties", bus_properties_interface,
56 "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
57 "org.freedesktop.systemd1.Manager", bus_manager_interface,
58 "org.freedesktop.systemd1.Job", bus_job_interface,
59 "org.freedesktop.systemd1.Unit", bus_unit_interface,
60 "org.freedesktop.systemd1.Service", bus_service_interface,
61 "org.freedesktop.systemd1.Socket", bus_socket_interface,
62 "org.freedesktop.systemd1.Target", bus_target_interface,
63 "org.freedesktop.systemd1.Device", bus_device_interface,
64 "org.freedesktop.systemd1.Mount", bus_mount_interface,
65 "org.freedesktop.systemd1.Automount", bus_automount_interface,
66 "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface,
67 "org.freedesktop.systemd1.Swap", bus_swap_interface,
871d7de4 68 "org.freedesktop.systemd1.Timer", bus_timer_interface,
01f78473 69 "org.freedesktop.systemd1.Path", bus_path_interface,
4288f619
LP
70 NULL
71};
ea430986 72
5e8d1c9a
LP
73static void bus_done_api(Manager *m);
74static void bus_done_system(Manager *m);
75static void bus_done_private(Manager *m);
923f8d76 76static void shutdown_connection(Manager *m, DBusConnection *c);
0034c15c 77
5e8d1c9a 78static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
8e274523
LP
79 Manager *m = data;
80
81 assert(bus);
82 assert(m);
2e317f52 83
5e8d1c9a
LP
84 /* We maintain two sets, one for those connections where we
85 * requested a dispatch, and another where we didn't. And then,
86 * we move the connections between the two sets. */
8e274523 87
5e8d1c9a
LP
88 if (status == DBUS_DISPATCH_COMPLETE)
89 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
90 else
91 set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
8e274523
LP
92}
93
ea430986
LP
94void bus_watch_event(Manager *m, Watch *w, int events) {
95 assert(m);
96 assert(w);
97
98 /* This is called by the event loop whenever there is
99 * something happening on D-Bus' file handles. */
100
8e274523 101 if (!dbus_watch_get_enabled(w->data.bus_watch))
ea430986
LP
102 return;
103
3df5bf61 104 dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
ea430986
LP
105}
106
107static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
108 Manager *m = data;
109 Watch *w;
110 struct epoll_event ev;
111
112 assert(bus_watch);
113 assert(m);
114
115 if (!(w = new0(Watch, 1)))
116 return FALSE;
117
118 w->fd = dbus_watch_get_unix_fd(bus_watch);
119 w->type = WATCH_DBUS_WATCH;
120 w->data.bus_watch = bus_watch;
121
122 zero(ev);
123 ev.events = bus_flags_to_events(bus_watch);
124 ev.data.ptr = w;
125
126 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
127
128 if (errno != EEXIST) {
129 free(w);
130 return FALSE;
131 }
132
133 /* Hmm, bloody D-Bus creates multiple watches on the
134 * same fd. epoll() does not like that. As a dirty
135 * hack we simply dup() the fd and hence get a second
136 * one we can safely add to the epoll(). */
137
138 if ((w->fd = dup(w->fd)) < 0) {
139 free(w);
140 return FALSE;
141 }
142
143 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
ea430986 144 close_nointr_nofail(w->fd);
da19d5c1 145 free(w);
ea430986
LP
146 return FALSE;
147 }
148
149 w->fd_is_dupped = true;
150 }
151
152 dbus_watch_set_data(bus_watch, w, NULL);
153
154 return TRUE;
155}
156
157static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
158 Manager *m = data;
159 Watch *w;
160
161 assert(bus_watch);
162 assert(m);
163
3df5bf61
LP
164 w = dbus_watch_get_data(bus_watch);
165 if (!w)
ea430986
LP
166 return;
167
168 assert(w->type == WATCH_DBUS_WATCH);
169 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
170
171 if (w->fd_is_dupped)
172 close_nointr_nofail(w->fd);
173
174 free(w);
175}
176
177static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
178 Manager *m = data;
179 Watch *w;
180 struct epoll_event ev;
181
182 assert(bus_watch);
183 assert(m);
184
3df5bf61
LP
185 w = dbus_watch_get_data(bus_watch);
186 if (!w)
187 return;
188
ea430986
LP
189 assert(w->type == WATCH_DBUS_WATCH);
190
191 zero(ev);
192 ev.events = bus_flags_to_events(bus_watch);
193 ev.data.ptr = w;
194
195 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
196}
197
198static int bus_timeout_arm(Manager *m, Watch *w) {
199 struct itimerspec its;
200
201 assert(m);
202 assert(w);
203
204 zero(its);
205
206 if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
207 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
da19d5c1 208 its.it_interval = its.it_value;
ea430986
LP
209 }
210
211 if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
212 return -errno;
213
214 return 0;
215}
216
217void bus_timeout_event(Manager *m, Watch *w, int events) {
218 assert(m);
219 assert(w);
220
221 /* This is called by the event loop whenever there is
222 * something happening on D-Bus' file handles. */
223
224 if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
225 return;
226
227 dbus_timeout_handle(w->data.bus_timeout);
228}
229
230static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
231 Manager *m = data;
232 Watch *w;
233 struct epoll_event ev;
234
235 assert(timeout);
236 assert(m);
237
238 if (!(w = new0(Watch, 1)))
239 return FALSE;
240
da19d5c1 241 if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
ea430986
LP
242 goto fail;
243
244 w->type = WATCH_DBUS_TIMEOUT;
245 w->data.bus_timeout = timeout;
246
247 if (bus_timeout_arm(m, w) < 0)
248 goto fail;
249
250 zero(ev);
251 ev.events = EPOLLIN;
252 ev.data.ptr = w;
253
254 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
255 goto fail;
256
257 dbus_timeout_set_data(timeout, w, NULL);
258
259 return TRUE;
260
261fail:
262 if (w->fd >= 0)
263 close_nointr_nofail(w->fd);
264
265 free(w);
266 return FALSE;
267}
268
269static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
270 Manager *m = data;
271 Watch *w;
272
273 assert(timeout);
274 assert(m);
275
3df5bf61
LP
276 w = dbus_timeout_get_data(timeout);
277 if (!w)
ea430986
LP
278 return;
279
280 assert(w->type == WATCH_DBUS_TIMEOUT);
3df5bf61 281
ea430986
LP
282 assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
283 close_nointr_nofail(w->fd);
284 free(w);
285}
286
287static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
288 Manager *m = data;
289 Watch *w;
290 int r;
291
292 assert(timeout);
293 assert(m);
294
3df5bf61
LP
295 w = dbus_timeout_get_data(timeout);
296 if (!w)
297 return;
298
ea430986
LP
299 assert(w->type == WATCH_DBUS_TIMEOUT);
300
301 if ((r = bus_timeout_arm(m, w)) < 0)
302 log_error("Failed to rearm timer: %s", strerror(-r));
303}
304
cf3e2471 305static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
c1e1601e
LP
306 Manager *m = data;
307 DBusError error;
0034c15c 308 DBusMessage *reply = NULL;
c1e1601e
LP
309
310 assert(connection);
311 assert(message);
312 assert(m);
313
314 dbus_error_init(&error);
315
1e001f52
LP
316 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
317 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
318 log_debug("Got D-Bus request: %s.%s() on %s",
319 dbus_message_get_interface(message),
320 dbus_message_get_member(message),
321 dbus_message_get_path(message));
c1e1601e
LP
322
323 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
9028d0ec 324 log_debug("API D-Bus connection terminated.");
f278026d 325 bus_done_api(m);
c1e1601e
LP
326
327 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
05e343b7 328 const char *name, *old_owner, *new_owner;
c1e1601e
LP
329
330 if (!dbus_message_get_args(message, &error,
331 DBUS_TYPE_STRING, &name,
05e343b7
LP
332 DBUS_TYPE_STRING, &old_owner,
333 DBUS_TYPE_STRING, &new_owner,
c1e1601e 334 DBUS_TYPE_INVALID))
a2e52832 335 log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
c1e1601e 336 else {
a567261a
LP
337 if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
338 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
05e343b7
LP
339
340 if (old_owner[0] == 0)
341 old_owner = NULL;
342
343 if (new_owner[0] == 0)
344 new_owner = NULL;
345
346 manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
c1e1601e 347 }
0034c15c
LP
348 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
349 const char *name;
350
351 if (!dbus_message_get_args(message, &error,
352 DBUS_TYPE_STRING, &name,
353 DBUS_TYPE_INVALID))
a2e52832 354 log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
0034c15c
LP
355 else {
356 int r;
357 Unit *u;
358
46018844
LP
359 log_debug("Got D-Bus activation request for %s", name);
360
8f6df3fa
LP
361 if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) ||
362 manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) {
363 r = -EADDRNOTAVAIL;
364 dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
365 } else {
366 r = manager_load_unit(m, name, NULL, &error, &u);
0034c15c 367
8f6df3fa
LP
368 if (r >= 0 && u->meta.refuse_manual_start)
369 r = -EPERM;
0034c15c 370
8f6df3fa
LP
371 if (r >= 0)
372 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
373 }
0034c15c
LP
374
375 if (r < 0) {
376 const char *id, *text;
377
2a8cd298 378 log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
af25ec12 379
0034c15c
LP
380 if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
381 goto oom;
382
bfebab7f 383 id = error.name ? error.name : bus_errno_to_dbus(r);
398ef8ba 384 text = bus_error(&error, r);
0034c15c
LP
385
386 if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
387 !dbus_message_append_args(reply,
388 DBUS_TYPE_STRING, &name,
389 DBUS_TYPE_STRING, &id,
390 DBUS_TYPE_STRING, &text,
391 DBUS_TYPE_INVALID))
392 goto oom;
393 }
394
35b8ca3a 395 /* On success we don't do anything, the service will be spawned now */
0034c15c 396 }
c1e1601e
LP
397 }
398
399 dbus_error_free(&error);
0034c15c
LP
400
401 if (reply) {
402 if (!dbus_connection_send(connection, reply, NULL))
403 goto oom;
404
405 dbus_message_unref(reply);
406 }
407
c1e1601e 408 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
0034c15c
LP
409
410oom:
411 if (reply)
412 dbus_message_unref(reply);
413
414 dbus_error_free(&error);
415
416 return DBUS_HANDLER_RESULT_NEED_MEMORY;
c1e1601e
LP
417}
418
cf3e2471 419static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
8e274523
LP
420 Manager *m = data;
421 DBusError error;
422
423 assert(connection);
424 assert(message);
425 assert(m);
426
427 dbus_error_init(&error);
428
1e001f52
LP
429 if (m->api_bus != m->system_bus &&
430 (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
431 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
432 log_debug("Got D-Bus request on system bus: %s.%s() on %s",
433 dbus_message_get_interface(message),
434 dbus_message_get_member(message),
435 dbus_message_get_path(message));
8e274523
LP
436
437 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
91805b3b 438 log_debug("System D-Bus connection terminated.");
f278026d 439 bus_done_system(m);
8e274523 440
53c6a358
LP
441 } else if (m->running_as != MANAGER_SYSTEM &&
442 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
443
8e274523
LP
444 const char *cgroup;
445
446 if (!dbus_message_get_args(message, &error,
447 DBUS_TYPE_STRING, &cgroup,
448 DBUS_TYPE_INVALID))
19bc719e 449 log_error("Failed to parse Released message: %s", bus_error_message(&error));
8e274523
LP
450 else
451 cgroup_notify_empty(m, cgroup);
452 }
453
454 dbus_error_free(&error);
455 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
456}
457
5e8d1c9a
LP
458static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
459 Manager *m = data;
3c661fad 460 DBusError error;
5e8d1c9a
LP
461
462 assert(connection);
463 assert(message);
464 assert(m);
465
3c661fad
LP
466 dbus_error_init(&error);
467
1e001f52
LP
468 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
469 dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
470 log_debug("Got D-Bus request: %s.%s() on %s",
471 dbus_message_get_interface(message),
472 dbus_message_get_member(message),
473 dbus_message_get_path(message));
5e8d1c9a 474
923f8d76
LP
475 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
476 shutdown_connection(m, connection);
53c6a358
LP
477 else if (m->running_as == MANAGER_SYSTEM &&
478 dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
479
3c661fad
LP
480 const char *cgroup;
481
482 if (!dbus_message_get_args(message, &error,
483 DBUS_TYPE_STRING, &cgroup,
484 DBUS_TYPE_INVALID))
a2e52832 485 log_error("Failed to parse Released message: %s", bus_error_message(&error));
3c661fad
LP
486 else
487 cgroup_notify_empty(m, cgroup);
53c6a358
LP
488
489 /* Forward the message to the system bus, so that user
490 * instances are notified as well */
491
492 if (m->system_bus)
493 dbus_connection_send(m->system_bus, message, NULL);
3c661fad
LP
494 }
495
496 dbus_error_free(&error);
5e8d1c9a
LP
497
498 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499}
500
c1e1601e 501unsigned bus_dispatch(Manager *m) {
5e8d1c9a
LP
502 DBusConnection *c;
503
ea430986
LP
504 assert(m);
505
a16e1123
LP
506 if (m->queued_message) {
507 /* If we cannot get rid of this message we won't
508 * dispatch any D-Bus messages, so that we won't end
509 * up wanting to queue another message. */
510
7b97f477
LP
511 if (m->queued_message_connection)
512 if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
5e8d1c9a 513 return 0;
a16e1123
LP
514
515 dbus_message_unref(m->queued_message);
516 m->queued_message = NULL;
7b97f477 517 m->queued_message_connection = NULL;
a16e1123
LP
518 }
519
5e8d1c9a
LP
520 if ((c = set_first(m->bus_connections_for_dispatch))) {
521 if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
522 set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
fd18e1f4
LP
523
524 return 1;
525 }
c1e1601e 526
8e274523 527 return 0;
ea430986
LP
528}
529
05e343b7 530static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
61902ea3
LP
531 DBusMessage *reply;
532 DBusError error;
533
534 dbus_error_init(&error);
535
536 assert_se(reply = dbus_pending_call_steal_reply(pending));
537
538 switch (dbus_message_get_type(reply)) {
539
540 case DBUS_MESSAGE_TYPE_ERROR:
541
542 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 543 log_warning("RequestName() failed: %s", bus_error_message(&error));
61902ea3
LP
544 break;
545
546 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
547 uint32_t r;
548
549 if (!dbus_message_get_args(reply,
550 &error,
551 DBUS_TYPE_UINT32, &r,
552 DBUS_TYPE_INVALID)) {
a2e52832 553 log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error));
61902ea3
LP
554 break;
555 }
556
557 if (r == 1)
558 log_debug("Successfully acquired name.");
559 else
560 log_error("Name already owned.");
561
562 break;
563 }
564
565 default:
566 assert_not_reached("Invalid reply message");
567 }
568
569 dbus_message_unref(reply);
570 dbus_error_free(&error);
571}
572
ea430986 573static int request_name(Manager *m) {
ea430986 574 const char *name = "org.freedesktop.systemd1";
b23de6af
LP
575 /* Allow replacing of our name, to ease implementation of
576 * reexecution, where we keep the old connection open until
577 * after the new connection is set up and the name installed
578 * to allow clients to synchronously wait for reexecution to
579 * finish */
580 uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
05e343b7
LP
581 DBusMessage *message = NULL;
582 DBusPendingCall *pending = NULL;
ea430986
LP
583
584 if (!(message = dbus_message_new_method_call(
585 DBUS_SERVICE_DBUS,
586 DBUS_PATH_DBUS,
587 DBUS_INTERFACE_DBUS,
588 "RequestName")))
05e343b7 589 goto oom;
ea430986
LP
590
591 if (!dbus_message_append_args(
592 message,
593 DBUS_TYPE_STRING, &name,
594 DBUS_TYPE_UINT32, &flags,
05e343b7
LP
595 DBUS_TYPE_INVALID))
596 goto oom;
ea430986 597
05e343b7
LP
598 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
599 goto oom;
ea430986 600
05e343b7
LP
601 if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
602 goto oom;
ea430986
LP
603
604 dbus_message_unref(message);
61902ea3
LP
605 dbus_pending_call_unref(pending);
606
607 /* We simple ask for the name and don't wait for it. Sooner or
608 * later we'll have it. */
609
ea430986 610 return 0;
05e343b7
LP
611
612oom:
613 if (pending) {
614 dbus_pending_call_cancel(pending);
615 dbus_pending_call_unref(pending);
616 }
617
618 if (message)
619 dbus_message_unref(message);
620
621 return -ENOMEM;
ea430986
LP
622}
623
6dded4c7
LP
624static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
625 DBusMessage *reply;
626 DBusError error;
627 Manager *m = userdata;
628
629 assert(m);
630
631 dbus_error_init(&error);
632
633 assert_se(reply = dbus_pending_call_steal_reply(pending));
634
635 switch (dbus_message_get_type(reply)) {
636
637 case DBUS_MESSAGE_TYPE_ERROR:
638
639 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 640 log_warning("ListNames() failed: %s", bus_error_message(&error));
6dded4c7
LP
641 break;
642
643 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
644 int r;
645 char **l;
646
647 if ((r = bus_parse_strv(reply, &l)) < 0)
648 log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
649 else {
650 char **t;
651
652 STRV_FOREACH(t, l)
653 /* This is a bit hacky, we say the
654 * owner of the name is the name
655 * itself, because we don't want the
656 * extra traffic to figure out the
657 * real owner. */
658 manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
659
660 strv_free(l);
661 }
662
663 break;
664 }
665
666 default:
667 assert_not_reached("Invalid reply message");
668 }
669
670 dbus_message_unref(reply);
671 dbus_error_free(&error);
672}
673
674static int query_name_list(Manager *m) {
675 DBusMessage *message = NULL;
676 DBusPendingCall *pending = NULL;
677
678 /* Asks for the currently installed bus names */
679
680 if (!(message = dbus_message_new_method_call(
681 DBUS_SERVICE_DBUS,
682 DBUS_PATH_DBUS,
683 DBUS_INTERFACE_DBUS,
684 "ListNames")))
685 goto oom;
686
687 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
688 goto oom;
689
690 if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
691 goto oom;
692
693 dbus_message_unref(message);
694 dbus_pending_call_unref(pending);
695
696 /* We simple ask for the list and don't wait for it. Sooner or
697 * later we'll get it. */
698
699 return 0;
700
701oom:
702 if (pending) {
703 dbus_pending_call_cancel(pending);
704 dbus_pending_call_unref(pending);
705 }
706
707 if (message)
708 dbus_message_unref(message);
709
710 return -ENOMEM;
711}
712
8e274523
LP
713static int bus_setup_loop(Manager *m, DBusConnection *bus) {
714 assert(m);
715 assert(bus);
716
717 dbus_connection_set_exit_on_disconnect(bus, FALSE);
fd18e1f4 718
8e274523 719 if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
5e8d1c9a
LP
720 !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
721 log_error("Not enough memory");
8e274523 722 return -ENOMEM;
5e8d1c9a 723 }
8e274523 724
5e8d1c9a
LP
725 if (set_put(m->bus_connections_for_dispatch, bus) < 0) {
726 log_error("Not enough memory");
727 return -ENOMEM;
728 }
729
730 dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
8e274523
LP
731 return 0;
732}
733
be81bfc4
LP
734static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
735 return uid == 0 || uid == geteuid();
5e8d1c9a
LP
736}
737
738static void bus_new_connection(
739 DBusServer *server,
740 DBusConnection *new_connection,
741 void *data) {
742
743 Manager *m = data;
744
745 assert(m);
746
747 if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
748 log_error("Too many concurrent connections.");
749 return;
750 }
751
be81bfc4 752 dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
5e8d1c9a
LP
753
754 if (bus_setup_loop(m, new_connection) < 0)
755 return;
756
757 if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
758 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
759 !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
760 !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
761 log_error("Not enough memory.");
762 return;
763 }
764
765 log_debug("Accepted connection on private bus.");
766
767 dbus_connection_ref(new_connection);
768}
769
770static int bus_init_system(Manager *m) {
ea430986 771 DBusError error;
ea430986
LP
772 int r;
773
774 assert(m);
775
ea430986 776 dbus_error_init(&error);
ea430986 777
f278026d
LP
778 if (m->system_bus)
779 return 0;
8e274523 780
a3d4e06d 781 if (m->running_as == MANAGER_SYSTEM && m->api_bus)
f278026d
LP
782 m->system_bus = m->api_bus;
783 else {
8e274523 784 if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
a2e52832 785 log_debug("Failed to get system D-Bus connection, retrying later: %s", bus_error_message(&error));
5e8d1c9a
LP
786 r = 0;
787 goto fail;
8e274523
LP
788 }
789
5e8d1c9a
LP
790 if ((r = bus_setup_loop(m, m->system_bus)) < 0)
791 goto fail;
f278026d
LP
792 }
793
794 if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
5e8d1c9a 795 log_error("Not enough memory");
3df5bf61 796 r = -ENOMEM;
5e8d1c9a 797 goto fail;
c1e1601e
LP
798 }
799
53c6a358
LP
800 if (m->running_as != MANAGER_SYSTEM) {
801 dbus_bus_add_match(m->system_bus,
802 "type='signal',"
803 "interface='org.freedesktop.systemd1.Agent',"
804 "member='Released',"
805 "path='/org/freedesktop/systemd1/agent'",
806 &error);
807
808 if (dbus_error_is_set(&error)) {
a2e52832 809 log_error("Failed to register match: %s", bus_error_message(&error));
53c6a358
LP
810 r = -EIO;
811 goto fail;
812 }
ea430986
LP
813 }
814
9014a8bd
LP
815 if (m->api_bus != m->system_bus) {
816 char *id;
91805b3b 817 log_debug("Successfully connected to system D-Bus bus %s as %s",
9014a8bd
LP
818 strnull((id = dbus_connection_get_server_id(m->system_bus))),
819 strnull(dbus_bus_get_unique_name(m->system_bus)));
820 dbus_free(id);
821 }
f278026d 822
f278026d 823 return 0;
5e8d1c9a
LP
824
825fail:
826 bus_done_system(m);
827 dbus_error_free(&error);
828
829 return r;
f278026d
LP
830}
831
5e8d1c9a 832static int bus_init_api(Manager *m) {
f278026d 833 DBusError error;
f278026d
LP
834 int r;
835
836 assert(m);
837
838 dbus_error_init(&error);
839
840 if (m->api_bus)
841 return 0;
842
a3d4e06d 843 if (m->running_as == MANAGER_SYSTEM && m->system_bus)
f278026d
LP
844 m->api_bus = m->system_bus;
845 else {
af2d49f7 846 if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_USER ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
a2e52832 847 log_debug("Failed to get API D-Bus connection, retrying later: %s", bus_error_message(&error));
5e8d1c9a
LP
848 r = 0;
849 goto fail;
f278026d
LP
850 }
851
5e8d1c9a
LP
852 if ((r = bus_setup_loop(m, m->api_bus)) < 0)
853 goto fail;
ea430986
LP
854 }
855
f278026d
LP
856 if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
857 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
858 !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
859 !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) {
5e8d1c9a
LP
860 log_error("Not enough memory");
861 r = -ENOMEM;
862 goto fail;
f278026d
LP
863 }
864
0034c15c 865 /* Get NameOwnerChange messages */
f278026d 866 dbus_bus_add_match(m->api_bus,
8e274523 867 "type='signal',"
f278026d
LP
868 "sender='"DBUS_SERVICE_DBUS"',"
869 "interface='"DBUS_INTERFACE_DBUS"',"
fd0d7f7a 870 "member='NameOwnerChanged',"
f278026d 871 "path='"DBUS_PATH_DBUS"'",
8e274523
LP
872 &error);
873
874 if (dbus_error_is_set(&error)) {
a2e52832 875 log_error("Failed to register match: %s", bus_error_message(&error));
5e8d1c9a
LP
876 r = -EIO;
877 goto fail;
8e274523
LP
878 }
879
0034c15c
LP
880 /* Get activation requests */
881 dbus_bus_add_match(m->api_bus,
882 "type='signal',"
883 "sender='"DBUS_SERVICE_DBUS"',"
884 "interface='org.freedesktop.systemd1.Activator',"
cf3e2471 885 "member='ActivationRequest',"
0034c15c
LP
886 "path='"DBUS_PATH_DBUS"'",
887 &error);
888
889 if (dbus_error_is_set(&error)) {
a2e52832 890 log_error("Failed to register match: %s", bus_error_message(&error));
5e8d1c9a
LP
891 r = -EIO;
892 goto fail;
0034c15c
LP
893 }
894
5e8d1c9a
LP
895 if ((r = request_name(m)) < 0)
896 goto fail;
ea430986 897
5e8d1c9a
LP
898 if ((r = query_name_list(m)) < 0)
899 goto fail;
6dded4c7 900
9014a8bd
LP
901 if (m->api_bus != m->system_bus) {
902 char *id;
91805b3b 903 log_debug("Successfully connected to API D-Bus bus %s as %s",
9014a8bd
LP
904 strnull((id = dbus_connection_get_server_id(m->api_bus))),
905 strnull(dbus_bus_get_unique_name(m->api_bus)));
906 dbus_free(id);
907 }
8e274523 908
5e8d1c9a
LP
909 return 0;
910
911fail:
912 bus_done_api(m);
913 dbus_error_free(&error);
914
915 return r;
916}
917
918static int bus_init_private(Manager *m) {
919 DBusError error;
920 int r;
921 const char *const external_only[] = {
922 "EXTERNAL",
923 NULL
924 };
925
926 assert(m);
927
928 dbus_error_init(&error);
929
930 if (m->private_bus)
931 return 0;
932
be81bfc4
LP
933 if (m->running_as == MANAGER_SYSTEM) {
934
935 /* We want the private bus only when running as init */
936 if (getpid() != 1)
937 return 0;
938
939 unlink("/run/systemd/private");
940 m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
941 } else {
942 const char *e;
943 char *p;
944
945 e = getenv("XDG_RUNTIME_DIR");
946 if (!e)
947 return 0;
948
949 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) {
950 log_error("Not enough memory");
951 r = -ENOMEM;
952 goto fail;
953 }
954
955 mkdir_parents(p+10, 0755);
956 unlink(p+10);
957 m->private_bus = dbus_server_listen(p, &error);
958 free(p);
959 }
5e8d1c9a 960
be81bfc4 961 if (!m->private_bus) {
a2e52832 962 log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
5e8d1c9a
LP
963 r = -EIO;
964 goto fail;
965 }
966
967 if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
968 !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
969 !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
970 log_error("Not enough memory");
971 r = -ENOMEM;
972 goto fail;
973 }
974
975 dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
976
54165a39 977 log_debug("Successfully created private D-Bus server.");
5e8d1c9a
LP
978
979 return 0;
980
981fail:
982 bus_done_private(m);
983 dbus_error_free(&error);
984
985 return r;
986}
987
3996fbe2 988int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
989 int r;
990
991 if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
992 set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0) {
993 log_error("Not enough memory");
994 return -ENOMEM;
995 }
996
997 if (m->name_data_slot < 0)
998 if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot)) {
999 log_error("Not enough memory");
f278026d 1000 return -ENOMEM;
5e8d1c9a
LP
1001 }
1002
a567261a 1003 if (m->subscribed_data_slot < 0)
d83685ac 1004 if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot)) {
a567261a
LP
1005 log_error("Not enough memory");
1006 return -ENOMEM;
1007 }
1008
3996fbe2
LP
1009 if (try_bus_connect) {
1010 if ((r = bus_init_system(m)) < 0 ||
1011 (r = bus_init_api(m)) < 0)
1012 return r;
1013 }
1014
1015 if ((r = bus_init_private(m)) < 0)
5e8d1c9a 1016 return r;
f278026d 1017
ea430986
LP
1018 return 0;
1019}
1020
fae20b11 1021static void shutdown_connection(Manager *m, DBusConnection *c) {
a567261a
LP
1022 Set *s;
1023 Job *j;
1024 Iterator i;
1025
1026 HASHMAP_FOREACH(j, m->jobs, i)
1027 if (j->bus == c) {
1028 free(j->bus_client);
1029 j->bus_client = NULL;
1030
1031 j->bus = NULL;
1032 }
1033
fae20b11
LP
1034 set_remove(m->bus_connections, c);
1035 set_remove(m->bus_connections_for_dispatch, c);
1036
a567261a
LP
1037 if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
1038 char *t;
1039
1040 while ((t = set_steal_first(s)))
1041 free(t);
1042
1043 set_free(s);
1044 }
1045
7b97f477
LP
1046 if (m->queued_message_connection == c) {
1047 m->queued_message_connection = NULL;
1048
1049 if (m->queued_message) {
1050 dbus_message_unref(m->queued_message);
1051 m->queued_message = NULL;
1052 }
1053 }
1054
5e8d1c9a
LP
1055 dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
1056 dbus_connection_flush(c);
1057 dbus_connection_close(c);
1058 dbus_connection_unref(c);
1059}
1060
1061static void bus_done_api(Manager *m) {
ea430986
LP
1062 assert(m);
1063
f278026d
LP
1064 if (m->api_bus) {
1065 if (m->system_bus == m->api_bus)
1066 m->system_bus = NULL;
1067
fae20b11 1068 shutdown_connection(m, m->api_bus);
f278026d 1069 m->api_bus = NULL;
ea430986 1070 }
c1e1601e 1071
05e343b7 1072
a16e1123
LP
1073 if (m->queued_message) {
1074 dbus_message_unref(m->queued_message);
1075 m->queued_message = NULL;
1076 }
ea430986
LP
1077}
1078
5e8d1c9a 1079static void bus_done_system(Manager *m) {
f278026d
LP
1080 assert(m);
1081
1082 if (m->system_bus == m->api_bus)
1083 bus_done_api(m);
1084
1085 if (m->system_bus) {
fae20b11 1086 shutdown_connection(m, m->system_bus);
f278026d
LP
1087 m->system_bus = NULL;
1088 }
1089}
1090
5e8d1c9a
LP
1091static void bus_done_private(Manager *m) {
1092
1093 if (m->private_bus) {
1094 dbus_server_disconnect(m->private_bus);
1095 dbus_server_unref(m->private_bus);
1096 m->private_bus = NULL;
1097 }
1098}
1099
1100void bus_done(Manager *m) {
1101 DBusConnection *c;
1102
1103 bus_done_api(m);
1104 bus_done_system(m);
1105 bus_done_private(m);
1106
1107 while ((c = set_steal_first(m->bus_connections)))
fae20b11 1108 shutdown_connection(m, c);
5e8d1c9a
LP
1109
1110 while ((c = set_steal_first(m->bus_connections_for_dispatch)))
fae20b11 1111 shutdown_connection(m, c);
5e8d1c9a
LP
1112
1113 set_free(m->bus_connections);
1114 set_free(m->bus_connections_for_dispatch);
1115
1116 if (m->name_data_slot >= 0)
1117 dbus_pending_call_free_data_slot(&m->name_data_slot);
a567261a
LP
1118
1119 if (m->subscribed_data_slot >= 0)
d83685ac 1120 dbus_connection_free_data_slot(&m->subscribed_data_slot);
5e8d1c9a
LP
1121}
1122
05e343b7
LP
1123static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
1124 Manager *m = userdata;
1125 DBusMessage *reply;
1126 DBusError error;
1127 const char *name;
1128
1129 dbus_error_init(&error);
1130
a567261a 1131 assert_se(name = BUS_PENDING_CALL_NAME(m, pending));
05e343b7
LP
1132 assert_se(reply = dbus_pending_call_steal_reply(pending));
1133
1134 switch (dbus_message_get_type(reply)) {
1135
1136 case DBUS_MESSAGE_TYPE_ERROR:
1137
1138 assert_se(dbus_set_error_from_message(&error, reply));
a2e52832 1139 log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error));
05e343b7
LP
1140 break;
1141
1142 case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
1143 uint32_t r;
1144
1145 if (!dbus_message_get_args(reply,
1146 &error,
1147 DBUS_TYPE_UINT32, &r,
1148 DBUS_TYPE_INVALID)) {
a2e52832 1149 log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error));
05e343b7
LP
1150 break;
1151 }
1152
1153 manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
1154 break;
1155 }
1156
1157 default:
1158 assert_not_reached("Invalid reply message");
1159 }
1160
1161 dbus_message_unref(reply);
1162 dbus_error_free(&error);
1163}
1164
1165int bus_query_pid(Manager *m, const char *name) {
1166 DBusMessage *message = NULL;
1167 DBusPendingCall *pending = NULL;
1168 char *n = NULL;
1169
1170 assert(m);
1171 assert(name);
1172
1173 if (!(message = dbus_message_new_method_call(
1174 DBUS_SERVICE_DBUS,
1175 DBUS_PATH_DBUS,
1176 DBUS_INTERFACE_DBUS,
1177 "GetConnectionUnixProcessID")))
1178 goto oom;
1179
1180 if (!(dbus_message_append_args(
1181 message,
1182 DBUS_TYPE_STRING, &name,
1183 DBUS_TYPE_INVALID)))
1184 goto oom;
1185
1186 if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
1187 goto oom;
1188
1189 if (!(n = strdup(name)))
1190 goto oom;
1191
1192 if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
1193 goto oom;
1194
1195 n = NULL;
1196
1197 if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
1198 goto oom;
1199
1200 dbus_message_unref(message);
1201 dbus_pending_call_unref(pending);
1202
1203 return 0;
1204
1205oom:
1206 free(n);
1207
1208 if (pending) {
1209 dbus_pending_call_cancel(pending);
1210 dbus_pending_call_unref(pending);
1211 }
1212
1213 if (message)
1214 dbus_message_unref(message);
1215
1216 return -ENOMEM;
1217}
1218
5e8d1c9a
LP
1219int bus_broadcast(Manager *m, DBusMessage *message) {
1220 bool oom = false;
1221 Iterator i;
1222 DBusConnection *c;
1223
1224 assert(m);
1225 assert(message);
1226
1227 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
a3d4e06d 1228 if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
5e8d1c9a
LP
1229 oom = !dbus_connection_send(c, message, NULL);
1230
1231 SET_FOREACH(c, m->bus_connections, i)
a3d4e06d 1232 if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
5e8d1c9a
LP
1233 oom = !dbus_connection_send(c, message, NULL);
1234
1235 return oom ? -ENOMEM : 0;
1236}
1237
a567261a
LP
1238bool bus_has_subscriber(Manager *m) {
1239 Iterator i;
1240 DBusConnection *c;
1241
1242 assert(m);
1243
1244 SET_FOREACH(c, m->bus_connections_for_dispatch, i)
1245 if (bus_connection_has_subscriber(m, c))
1246 return true;
1247
1248 SET_FOREACH(c, m->bus_connections, i)
1249 if (bus_connection_has_subscriber(m, c))
1250 return true;
1251
1252 return false;
1253}
1254
1255bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
1256 assert(m);
1257 assert(c);
1258
1259 return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
1260}
b23de6af
LP
1261
1262int bus_fdset_add_all(Manager *m, FDSet *fds) {
1263 Iterator i;
1264 DBusConnection *c;
1265
1266 assert(m);
1267 assert(fds);
1268
1269 /* When we are about to reexecute we add all D-Bus fds to the
1270 * set to pass over to the newly executed systemd. They won't
1271 * be used there however, except that they are closed at the
1272 * very end of deserialization, those making it possible for
44143309 1273 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1274 * simply waiting for disconnection */
1275
1276 SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
1277 int fd;
1278
1279 if (dbus_connection_get_unix_fd(c, &fd)) {
1280 fd = fdset_put_dup(fds, fd);
1281
1282 if (fd < 0)
1283 return fd;
1284 }
1285 }
1286
1287 SET_FOREACH(c, m->bus_connections, i) {
1288 int fd;
1289
1290 if (dbus_connection_get_unix_fd(c, &fd)) {
1291 fd = fdset_put_dup(fds, fd);
1292
1293 if (fd < 0)
1294 return fd;
1295 }
1296 }
1297
1298 return 0;
1299}
18fa6b27
LP
1300
1301void bus_broadcast_finished(
1302 Manager *m,
1303 usec_t kernel_usec,
1304 usec_t initrd_usec,
1305 usec_t userspace_usec,
1306 usec_t total_usec) {
1307
1308 DBusMessage *message;
1309
1310 assert(m);
1311
1312 message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
1313 if (!message) {
1314 log_error("Out of memory.");
1315 return;
1316 }
1317
1318 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
1319 if (!dbus_message_append_args(message,
1320 DBUS_TYPE_UINT64, &kernel_usec,
1321 DBUS_TYPE_UINT64, &initrd_usec,
1322 DBUS_TYPE_UINT64, &userspace_usec,
1323 DBUS_TYPE_UINT64, &total_usec,
1324 DBUS_TYPE_INVALID)) {
1325 log_error("Out of memory.");
1326 goto finish;
1327 }
1328
1329
1330 if (bus_broadcast(m, message) < 0) {
1331 log_error("Out of memory.");
1332 goto finish;
1333 }
1334
1335finish:
c99ddfaa 1336 if (message)
18fa6b27
LP
1337 dbus_message_unref(message);
1338}