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