1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
23 #include <sys/epoll.h>
28 #include "bus-common-errors.h"
29 #include "bus-error.h"
30 #include "bus-internal.h"
32 #include "dbus-cgroup.h"
33 #include "dbus-execute.h"
35 #include "dbus-kill.h"
36 #include "dbus-manager.h"
37 #include "dbus-unit.h"
43 #include "selinux-access.h"
45 #include "string-util.h"
48 #include "user-util.h"
50 #define CONNECTIONS_MAX 4096
52 static void destroy_bus(Manager
*m
, sd_bus
**bus
);
54 int bus_send_queued_message(Manager
*m
) {
59 if (!m
->queued_message
)
62 /* If we cannot get rid of this message we won't dispatch any
63 * D-Bus messages, so that we won't end up wanting to queue
66 r
= sd_bus_send(NULL
, m
->queued_message
, NULL
);
68 log_warning_errno(r
, "Failed to send queued message: %m");
70 m
->queued_message
= sd_bus_message_unref(m
->queued_message
);
75 static int signal_agent_released(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
76 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
77 const char *cgroup
, *me
;
78 Manager
*m
= userdata
;
86 /* ignore recursive events sent by us on the system/user bus */
87 bus
= sd_bus_message_get_bus(message
);
88 if (!sd_bus_is_server(bus
)) {
89 r
= sd_bus_get_unique_name(bus
, &me
);
93 if (streq_ptr(sd_bus_message_get_sender(message
), me
))
97 /* only accept org.freedesktop.systemd1.Agent from UID=0 */
98 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
102 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
103 if (r
< 0 || sender_uid
!= 0)
106 /* parse 'cgroup-empty' notification */
107 r
= sd_bus_message_read(message
, "s", &cgroup
);
109 bus_log_parse_error(r
);
113 manager_notify_cgroup_empty(m
, cgroup
);
115 /* if running as system-instance, forward under our name */
116 if (m
->running_as
== MANAGER_SYSTEM
&& m
->system_bus
) {
117 r
= sd_bus_message_rewind(message
, 1);
119 r
= sd_bus_send(m
->system_bus
, message
, NULL
);
121 log_warning_errno(r
, "Failed to forward Released message: %m");
127 static int signal_disconnected(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
128 Manager
*m
= userdata
;
133 assert_se(bus
= sd_bus_message_get_bus(message
));
135 if (bus
== m
->api_bus
)
136 destroy_bus(m
, &m
->api_bus
);
137 if (bus
== m
->system_bus
)
138 destroy_bus(m
, &m
->system_bus
);
139 if (set_remove(m
->private_buses
, bus
)) {
140 log_debug("Got disconnect on private connection.");
141 destroy_bus(m
, &bus
);
147 static int signal_activation_request(sd_bus_message
*message
, void *userdata
, sd_bus_error
*ret_error
) {
148 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
149 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
150 Manager
*m
= userdata
;
158 r
= sd_bus_message_read(message
, "s", &name
);
160 bus_log_parse_error(r
);
164 if (manager_unit_inactive_or_pending(m
, SPECIAL_DBUS_SERVICE
) ||
165 manager_unit_inactive_or_pending(m
, SPECIAL_DBUS_SOCKET
)) {
166 r
= sd_bus_error_setf(&error
, BUS_ERROR_SHUTTING_DOWN
, "Refusing activation, D-Bus is shutting down.");
170 r
= manager_load_unit(m
, name
, NULL
, &error
, &u
);
174 if (u
->refuse_manual_start
) {
175 r
= sd_bus_error_setf(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, %s may be requested by dependency only.", u
->id
);
179 r
= manager_add_job(m
, JOB_START
, u
, JOB_REPLACE
, true, &error
, NULL
);
183 /* Successfully queued, that's it for us */
187 if (!sd_bus_error_is_set(&error
))
188 sd_bus_error_set_errno(&error
, r
);
190 log_debug("D-Bus activation failed for %s: %s", name
, bus_error_message(&error
, r
));
192 r
= sd_bus_message_new_signal(sd_bus_message_get_bus(message
), &reply
, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
194 bus_log_create_error(r
);
198 r
= sd_bus_message_append(reply
, "sss", name
, error
.name
, error
.message
);
200 bus_log_create_error(r
);
204 r
= sd_bus_send_to(NULL
, reply
, "org.freedesktop.DBus", NULL
);
206 return log_error_errno(r
, "Failed to respond with to bus activation request: %m");
212 static int mac_selinux_filter(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
213 Manager
*m
= userdata
;
214 const char *verb
, *path
;
221 /* Our own method calls are all protected individually with
222 * selinux checks, but the built-in interfaces need to be
225 if (sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Properties", "Set"))
227 else if (sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", NULL
) ||
228 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Properties", NULL
) ||
229 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.ObjectManager", NULL
) ||
230 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Peer", NULL
))
235 path
= sd_bus_message_get_path(message
);
237 if (object_path_startswith("/org/freedesktop/systemd1", path
)) {
239 r
= mac_selinux_access_check(message
, verb
, error
);
246 if (streq_ptr(path
, "/org/freedesktop/systemd1/unit/self")) {
247 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
250 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
254 r
= sd_bus_creds_get_pid(creds
, &pid
);
258 u
= manager_get_unit_by_pid(m
, pid
);
260 r
= manager_get_job_from_dbus_path(m
, path
, &j
);
264 manager_load_unit_from_dbus_path(m
, path
, NULL
, &u
);
270 r
= mac_selinux_unit_access_check(u
, message
, verb
, error
);
278 static int bus_job_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
279 Manager
*m
= userdata
;
289 r
= manager_get_job_from_dbus_path(m
, path
, &j
);
297 static int find_unit(Manager
*m
, sd_bus
*bus
, const char *path
, Unit
**unit
, sd_bus_error
*error
) {
305 if (streq_ptr(path
, "/org/freedesktop/systemd1/unit/self")) {
306 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
307 sd_bus_message
*message
;
310 message
= sd_bus_get_current_message(bus
);
314 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
318 r
= sd_bus_creds_get_pid(creds
, &pid
);
322 u
= manager_get_unit_by_pid(m
, pid
);
324 r
= manager_load_unit_from_dbus_path(m
, path
, error
, &u
);
336 static int bus_unit_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
337 Manager
*m
= userdata
;
345 return find_unit(m
, bus
, path
, (Unit
**) found
, error
);
348 static int bus_unit_interface_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
349 Manager
*m
= userdata
;
359 r
= find_unit(m
, bus
, path
, &u
, error
);
363 if (!streq_ptr(interface
, unit_dbus_interface_from_type(u
->type
)))
370 static int bus_unit_cgroup_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
371 Manager
*m
= userdata
;
381 r
= find_unit(m
, bus
, path
, &u
, error
);
385 if (!streq_ptr(interface
, unit_dbus_interface_from_type(u
->type
)))
388 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
395 static int bus_cgroup_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
396 Manager
*m
= userdata
;
407 r
= find_unit(m
, bus
, path
, &u
, error
);
411 if (!streq_ptr(interface
, unit_dbus_interface_from_type(u
->type
)))
414 c
= unit_get_cgroup_context(u
);
422 static int bus_exec_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
423 Manager
*m
= userdata
;
434 r
= find_unit(m
, bus
, path
, &u
, error
);
438 if (!streq_ptr(interface
, unit_dbus_interface_from_type(u
->type
)))
441 c
= unit_get_exec_context(u
);
449 static int bus_kill_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
450 Manager
*m
= userdata
;
461 r
= find_unit(m
, bus
, path
, &u
, error
);
465 if (!streq_ptr(interface
, unit_dbus_interface_from_type(u
->type
)))
468 c
= unit_get_kill_context(u
);
476 static int bus_job_enumerate(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
477 _cleanup_free_
char **l
= NULL
;
478 Manager
*m
= userdata
;
483 l
= new0(char*, hashmap_size(m
->jobs
)+1);
487 HASHMAP_FOREACH(j
, m
->jobs
, i
) {
488 l
[k
] = job_dbus_path(j
);
495 assert(hashmap_size(m
->jobs
) == k
);
503 static int bus_unit_enumerate(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
504 _cleanup_free_
char **l
= NULL
;
505 Manager
*m
= userdata
;
510 l
= new0(char*, hashmap_size(m
->units
)+1);
514 HASHMAP_FOREACH(u
, m
->units
, i
) {
515 l
[k
] = unit_dbus_path(u
);
528 static int bus_setup_api_vtables(Manager
*m
, sd_bus
*bus
) {
536 r
= sd_bus_add_filter(bus
, NULL
, mac_selinux_filter
, m
);
538 return log_error_errno(r
, "Failed to add SELinux access filter: %m");
541 r
= sd_bus_add_object_vtable(bus
, NULL
, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable
, m
);
543 return log_error_errno(r
, "Failed to register Manager vtable: %m");
545 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable
, bus_job_find
, m
);
547 return log_error_errno(r
, "Failed to register Job vtable: %m");
549 r
= sd_bus_add_node_enumerator(bus
, NULL
, "/org/freedesktop/systemd1/job", bus_job_enumerate
, m
);
551 return log_error_errno(r
, "Failed to add job enumerator: %m");
553 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable
, bus_unit_find
, m
);
555 return log_error_errno(r
, "Failed to register Unit vtable: %m");
557 r
= sd_bus_add_node_enumerator(bus
, NULL
, "/org/freedesktop/systemd1/unit", bus_unit_enumerate
, m
);
559 return log_error_errno(r
, "Failed to add job enumerator: %m");
561 for (t
= 0; t
< _UNIT_TYPE_MAX
; t
++) {
562 const char *interface
;
564 assert_se(interface
= unit_dbus_interface_from_type(t
));
566 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", interface
, unit_vtable
[t
]->bus_vtable
, bus_unit_interface_find
, m
);
568 return log_error_errno(r
, "Failed to register type specific vtable for %s: %m", interface
);
570 if (unit_vtable
[t
]->cgroup_context_offset
> 0) {
571 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", interface
, bus_unit_cgroup_vtable
, bus_unit_cgroup_find
, m
);
573 return log_error_errno(r
, "Failed to register control group unit vtable for %s: %m", interface
);
575 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", interface
, bus_cgroup_vtable
, bus_cgroup_context_find
, m
);
577 return log_error_errno(r
, "Failed to register control group vtable for %s: %m", interface
);
580 if (unit_vtable
[t
]->exec_context_offset
> 0) {
581 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", interface
, bus_exec_vtable
, bus_exec_context_find
, m
);
583 return log_error_errno(r
, "Failed to register execute vtable for %s: %m", interface
);
586 if (unit_vtable
[t
]->kill_context_offset
> 0) {
587 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", interface
, bus_kill_vtable
, bus_kill_context_find
, m
);
589 return log_error_errno(r
, "Failed to register kill vtable for %s: %m", interface
);
596 static int bus_setup_disconnected_match(Manager
*m
, sd_bus
*bus
) {
602 r
= sd_bus_add_match(
605 "sender='org.freedesktop.DBus.Local',"
607 "path='/org/freedesktop/DBus/Local',"
608 "interface='org.freedesktop.DBus.Local',"
609 "member='Disconnected'",
610 signal_disconnected
, m
);
613 return log_error_errno(r
, "Failed to register match for Disconnected message: %m");
618 static int bus_on_connection(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
619 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
620 _cleanup_close_
int nfd
= -1;
621 Manager
*m
= userdata
;
628 nfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
630 log_warning_errno(errno
, "Failed to accept private connection, ignoring: %m");
634 if (set_size(m
->private_buses
) >= CONNECTIONS_MAX
) {
635 log_warning("Too many concurrent connections, refusing");
639 r
= set_ensure_allocated(&m
->private_buses
, NULL
);
645 r
= sd_bus_new(&bus
);
647 log_warning_errno(r
, "Failed to allocate new private connection bus: %m");
651 r
= sd_bus_set_fd(bus
, nfd
, nfd
);
653 log_warning_errno(r
, "Failed to set fd on new connection bus: %m");
659 r
= bus_check_peercred(bus
);
661 log_warning_errno(r
, "Incoming private connection from unprivileged client, refusing: %m");
665 assert_se(sd_id128_randomize(&id
) >= 0);
667 r
= sd_bus_set_server(bus
, 1, id
);
669 log_warning_errno(r
, "Failed to enable server support for new connection bus: %m");
673 r
= sd_bus_negotiate_creds(bus
, 1,
674 SD_BUS_CREDS_PID
|SD_BUS_CREDS_UID
|
675 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
|
676 SD_BUS_CREDS_SELINUX_CONTEXT
);
678 log_warning_errno(r
, "Failed to enable credentials for new connection: %m");
682 r
= sd_bus_start(bus
);
684 log_warning_errno(r
, "Failed to start new connection bus: %m");
688 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
690 log_warning_errno(r
, "Failed to attach new connection bus to event loop: %m");
694 if (m
->running_as
== MANAGER_SYSTEM
) {
695 /* When we run as system instance we get the Released
696 * signal via a direct connection */
698 r
= sd_bus_add_match(
702 "interface='org.freedesktop.systemd1.Agent',"
704 "path='/org/freedesktop/systemd1/agent'",
705 signal_agent_released
, m
);
708 log_warning_errno(r
, "Failed to register Released match on new connection bus: %m");
713 r
= bus_setup_disconnected_match(m
, bus
);
717 r
= bus_setup_api_vtables(m
, bus
);
719 log_warning_errno(r
, "Failed to set up API vtables on new connection bus: %m");
723 r
= set_put(m
->private_buses
, bus
);
725 log_warning_errno(r
, "Failed to add new connection bus to set: %m");
731 log_debug("Accepted new private connection.");
736 static int bus_list_names(Manager
*m
, sd_bus
*bus
) {
737 _cleanup_strv_free_
char **names
= NULL
;
744 r
= sd_bus_list_names(bus
, &names
, NULL
);
746 return log_error_errno(r
, "Failed to get initial list of names: %m");
748 /* This is a bit hacky, we say the owner of the name is the
749 * name itself, because we don't want the extra traffic to
750 * figure out the real owner. */
751 STRV_FOREACH(i
, names
) {
754 u
= hashmap_get(m
->watch_bus
, *i
);
756 UNIT_VTABLE(u
)->bus_name_owner_change(u
, *i
, NULL
, *i
);
762 static int bus_setup_api(Manager
*m
, sd_bus
*bus
) {
771 /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
772 r
= sd_bus_negotiate_creds(bus
, 1,
773 SD_BUS_CREDS_PID
|SD_BUS_CREDS_UID
|
774 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
|
775 SD_BUS_CREDS_SELINUX_CONTEXT
);
777 log_warning_errno(r
, "Failed to enable credential passing, ignoring: %m");
779 r
= bus_setup_api_vtables(m
, bus
);
783 HASHMAP_FOREACH_KEY(u
, name
, m
->watch_bus
, i
) {
784 r
= unit_install_bus_match(u
, bus
, name
);
786 log_error_errno(r
, "Failed to subscribe to NameOwnerChanged signal: %m");
789 r
= sd_bus_add_match(
793 "sender='org.freedesktop.DBus',"
794 "path='/org/freedesktop/DBus',"
795 "interface='org.freedesktop.systemd1.Activator',"
796 "member='ActivationRequest'",
797 signal_activation_request
, m
);
799 log_warning_errno(r
, "Failed to subscribe to activation signal: %m");
801 /* Allow replacing of our name, to ease implementation of
802 * reexecution, where we keep the old connection open until
803 * after the new connection is set up and the name installed
804 * to allow clients to synchronously wait for reexecution to
806 r
= sd_bus_request_name(bus
,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING
|SD_BUS_NAME_ALLOW_REPLACEMENT
);
808 return log_error_errno(r
, "Failed to register name: %m");
810 bus_list_names(m
, bus
);
812 log_debug("Successfully connected to API bus.");
816 static int bus_init_api(Manager
*m
) {
817 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
823 /* The API and system bus is the same if we are running in system mode */
824 if (m
->running_as
== MANAGER_SYSTEM
&& m
->system_bus
)
825 bus
= sd_bus_ref(m
->system_bus
);
827 if (m
->running_as
== MANAGER_SYSTEM
)
828 r
= sd_bus_open_system(&bus
);
830 r
= sd_bus_open_user(&bus
);
833 log_debug("Failed to connect to API bus, retrying later...");
837 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
839 log_error_errno(r
, "Failed to attach API bus to event loop: %m");
843 r
= bus_setup_disconnected_match(m
, bus
);
848 r
= bus_setup_api(m
, bus
);
850 log_error_errno(r
, "Failed to set up API bus: %m");
860 static int bus_setup_system(Manager
*m
, sd_bus
*bus
) {
866 /* On kdbus or if we are a user instance we get the Released message via the system bus */
867 if (m
->running_as
== MANAGER_USER
|| m
->kdbus_fd
>= 0) {
868 r
= sd_bus_add_match(
872 "interface='org.freedesktop.systemd1.Agent',"
874 "path='/org/freedesktop/systemd1/agent'",
875 signal_agent_released
, m
);
877 log_warning_errno(r
, "Failed to register Released match on system bus: %m");
880 log_debug("Successfully connected to system bus.");
884 static int bus_init_system(Manager
*m
) {
885 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
891 /* The API and system bus is the same if we are running in system mode */
892 if (m
->running_as
== MANAGER_SYSTEM
&& m
->api_bus
) {
893 m
->system_bus
= sd_bus_ref(m
->api_bus
);
897 r
= sd_bus_open_system(&bus
);
899 log_debug("Failed to connect to system bus, retrying later...");
903 r
= bus_setup_disconnected_match(m
, bus
);
907 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
909 log_error_errno(r
, "Failed to attach system bus to event loop: %m");
913 r
= bus_setup_system(m
, bus
);
915 log_error_errno(r
, "Failed to set up system bus: %m");
925 static int bus_init_private(Manager
*m
) {
926 _cleanup_close_
int fd
= -1;
927 union sockaddr_union sa
= {
928 .un
.sun_family
= AF_UNIX
936 if (m
->private_listen_fd
>= 0)
939 /* We don't need the private socket if we have kdbus */
940 if (m
->kdbus_fd
>= 0)
943 if (m
->running_as
== MANAGER_SYSTEM
) {
945 /* We want the private bus only when running as init */
949 strcpy(sa
.un
.sun_path
, "/run/systemd/private");
950 salen
= offsetof(union sockaddr_union
, un
.sun_path
) + strlen("/run/systemd/private");
952 size_t left
= sizeof(sa
.un
.sun_path
);
953 char *p
= sa
.un
.sun_path
;
956 e
= secure_getenv("XDG_RUNTIME_DIR");
958 log_error("Failed to determine XDG_RUNTIME_DIR");
962 left
= strpcpy(&p
, left
, e
);
963 left
= strpcpy(&p
, left
, "/systemd/private");
965 salen
= sizeof(sa
.un
) - left
;
968 (void) mkdir_parents_label(sa
.un
.sun_path
, 0755);
969 (void) unlink(sa
.un
.sun_path
);
971 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
973 return log_error_errno(errno
, "Failed to allocate private socket: %m");
975 r
= bind(fd
, &sa
.sa
, salen
);
977 return log_error_errno(errno
, "Failed to bind private socket: %m");
979 r
= listen(fd
, SOMAXCONN
);
981 return log_error_errno(errno
, "Failed to make private socket listening: %m");
983 r
= sd_event_add_io(m
->event
, &s
, fd
, EPOLLIN
, bus_on_connection
, m
);
985 return log_error_errno(r
, "Failed to allocate event source: %m");
987 (void) sd_event_source_set_description(s
, "bus-connection");
989 m
->private_listen_fd
= fd
;
990 m
->private_listen_event_source
= s
;
993 log_debug("Successfully created private D-Bus server.");
998 int bus_init(Manager
*m
, bool try_bus_connect
) {
1001 if (try_bus_connect
) {
1002 r
= bus_init_system(m
);
1006 r
= bus_init_api(m
);
1011 r
= bus_init_private(m
);
1018 static void destroy_bus(Manager
*m
, sd_bus
**bus
) {
1028 /* Get rid of tracked clients on this bus */
1029 if (m
->subscribed
&& sd_bus_track_get_bus(m
->subscribed
) == *bus
)
1030 m
->subscribed
= sd_bus_track_unref(m
->subscribed
);
1032 HASHMAP_FOREACH(j
, m
->jobs
, i
)
1033 if (j
->clients
&& sd_bus_track_get_bus(j
->clients
) == *bus
)
1034 j
->clients
= sd_bus_track_unref(j
->clients
);
1036 /* Get rid of queued message on this bus */
1037 if (m
->queued_message
&& sd_bus_message_get_bus(m
->queued_message
) == *bus
)
1038 m
->queued_message
= sd_bus_message_unref(m
->queued_message
);
1040 /* Possibly flush unwritten data, but only if we are
1041 * unprivileged, since we don't want to sync here */
1042 if (m
->running_as
!= MANAGER_SYSTEM
)
1045 /* And destroy the object */
1047 *bus
= sd_bus_unref(*bus
);
1050 void bus_done(Manager
*m
) {
1056 destroy_bus(m
, &m
->api_bus
);
1058 destroy_bus(m
, &m
->system_bus
);
1059 while ((b
= set_steal_first(m
->private_buses
)))
1062 m
->private_buses
= set_free(m
->private_buses
);
1064 m
->subscribed
= sd_bus_track_unref(m
->subscribed
);
1065 m
->deserialized_subscribed
= strv_free(m
->deserialized_subscribed
);
1067 if (m
->private_listen_event_source
)
1068 m
->private_listen_event_source
= sd_event_source_unref(m
->private_listen_event_source
);
1070 m
->private_listen_fd
= safe_close(m
->private_listen_fd
);
1072 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
1075 int bus_fdset_add_all(Manager
*m
, FDSet
*fds
) {
1083 /* When we are about to reexecute we add all D-Bus fds to the
1084 * set to pass over to the newly executed systemd. They won't
1085 * be used there however, except thatt they are closed at the
1086 * very end of deserialization, those making it possible for
1087 * clients to synchronously wait for systemd to reexec by
1088 * simply waiting for disconnection */
1091 fd
= sd_bus_get_fd(m
->api_bus
);
1093 fd
= fdset_put_dup(fds
, fd
);
1099 SET_FOREACH(b
, m
->private_buses
, i
) {
1100 fd
= sd_bus_get_fd(b
);
1102 fd
= fdset_put_dup(fds
, fd
);
1108 /* We don't offer any APIs on the system bus (well, unless it
1109 * is the same as the API bus) hence we don't bother with it
1115 int bus_foreach_bus(
1117 sd_bus_track
*subscribed2
,
1118 int (*send_message
)(sd_bus
*bus
, void *userdata
),
1125 /* Send to all direct buses, unconditionally */
1126 SET_FOREACH(b
, m
->private_buses
, i
) {
1127 r
= send_message(b
, userdata
);
1132 /* Send to API bus, but only if somebody is subscribed */
1133 if (sd_bus_track_count(m
->subscribed
) > 0 ||
1134 sd_bus_track_count(subscribed2
) > 0) {
1135 r
= send_message(m
->api_bus
, userdata
);
1143 void bus_track_serialize(sd_bus_track
*t
, FILE *f
) {
1148 for (n
= sd_bus_track_first(t
); n
; n
= sd_bus_track_next(t
))
1149 fprintf(f
, "subscribed=%s\n", n
);
1152 int bus_track_deserialize_item(char ***l
, const char *line
) {
1159 e
= startswith(line
, "subscribed=");
1163 r
= strv_extend(l
, e
);
1170 int bus_track_coldplug(Manager
*m
, sd_bus_track
**t
, char ***l
) {
1177 if (!strv_isempty(*l
) && m
->api_bus
) {
1181 r
= sd_bus_track_new(m
->api_bus
, t
, NULL
, NULL
);
1187 STRV_FOREACH(i
, *l
) {
1190 k
= sd_bus_track_add_name(*t
, *i
);
1201 int bus_verify_manage_units_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1202 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.manage-units", NULL
, false, UID_INVALID
, &m
->polkit_registry
, error
);
1205 int bus_verify_manage_unit_files_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1206 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.manage-unit-files", NULL
, false, UID_INVALID
, &m
->polkit_registry
, error
);
1209 int bus_verify_reload_daemon_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1210 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.reload-daemon", NULL
, false, UID_INVALID
, &m
->polkit_registry
, error
);
1213 int bus_verify_set_environment_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1214 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.set-environment", NULL
, false, UID_INVALID
, &m
->polkit_registry
, error
);