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